一、程序,进程,线程的区别
程序是一段静态的代码,是软件执行的蓝本。
进程可以理解为正在进行的程序,它是从程序加载、执行、执行完毕的整个过程,多个进程可以共享操作系统所管理的资源,比如剪切板。每个进程都单独占用一块内存,多个进程之间不能数据共享,必须通过网络交换数据。
线程是比进程更小的执行单位,一个进程在执行过程中,可以产生多个线程。线程是一个进程内部的多个并行的运行单元,同一个进程的多个线程之间可以通过内存共享数据。通俗地讲,线程是运行在进程中的小“进程”。
二、Java中的多线程
Java程序执行时,先启动了一个主线程,即main方法。在main方法中,可以开启其他线程。当main方法执行完毕的时候,程序不会退出,只有所有线程都执行完毕,Java程序才会退出。
线程的使用方法:
1.继承Thread类
public class A extends Thread{ public void run(){ //线程要干的活... } } class Main{ public static void main(String args[]){ new A().start();//这样就执行了A中的run方法,当run执行完毕,线程结束 } }
2.实现Runnable接口
/** *刷新Jpanel的线程 * **/ public class UpdataCenter implements Runnable { JPanel center; public UpdataCenter(JPanel center) { this.center = center; } @Override public void run() { while (true) { if (!MainUI.pause) { center.repaint(); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } //调用 UpdataCenter st = new UpdataCenter(center); Thread th = new Thread(st); th.start();//开启线程
当有多个线程执行的时候,由于CPU每次只处理一个,他们的处理顺序是不确定的,所以先开启的线程不一定先执行。
当run方法执行完毕,线程变成死亡状态,释放了分配给线程对象的内存。如果在run未执行完重复调用start()会抛出IlIegalThreadStateException。
三、线程中的方法
sleep(long a);休眠a毫秒,再往下执行。
interrupt()可以吵醒休眠的线程,结束休眠。
isAlive();线程在执行run的过程中返回true,开始执行前和执行结束后返回false。
四、线程同步
同步:有多个线程同时操作一个变量,这个时候就没办法确定程序的正确性了,所以应该想办法解决这种 同时执行的时候对变量改变的不确定性,所以得先执行玩这个再执行其它,同时只做一件事。
异步:多线程可以同时操作,不会发生结果错误。、
比如在两个地方同时使用网银转账。本来银行卡剩余1000,在A处转出800,在B处转出500.最后本来卡内余额应该为-300。但是由于使用两个线程在同时取钱,这就造成了结果的不确定性。
线程A处从内存中读到money = 1000;对其进行-800的操作,money = 200;
线程B处从内存中读到money = 1000;对其进行-500的操作,money = 500;
两个线程计算完毕,将数据放回原地,而Cpu只能一次一次的放(同时只能处理一件事,只是速度非常快)CPU有可能先将200放回去,再将500放回去,那么卡内余额变成了500(200被覆盖),反之亦然。
当然,还有一种情况是,线程A处从内存中读到money = 1000;对其进行-800的操作,money = 200,将其放回原地;在进行B的操作(线程执行顺序具有不确定性)。这个时候卡内余额变成了-300。
如何避免第一种情况的发生?这就是线程同步需要处理的问题。
Java中提供了关键字synchronized(同步),使用该关键字可以修饰方法,对象。
使用它修饰之后,当一个线程取出了这个对象对其修改或者这个方法对其执行。其余线程必须等待它先执行完毕。这样就避免了第一种错误。
使用方法:
public class Main { public static void main(String[] args) { Account ac = new Account(); new Card(ac, 800).start(); new Card(ac, 400).start(); } } package Thread20140715; public class Card extends Thread { Account ac; int n; public Card(Account ac, int n) { this.ac = ac; this.n = n; } /** * 异步:可以同时修改这块内存,导致结果出错。 * * 如果没在Account锁定, * * 输出结果:-200 -200或者200 200或者600 600 * * 否则,结果为 200/600 -200 */ public void run() { ac.getMoney(n); ac.getMoney1(n); ac.getMoney2(n); } /** * 同步:只允许一个Account操作修改这块内存。 * * 输出结果: 200/600 -200 */ // public void run() { // synchronized (ac) {// 锁定ac // ac.getMoney(n); // } // } } package Thread20140715; public class Account { int money = 1000, money1 = 1000, money2 = 1000; /** * 异步 * * @param n * 要取多少钱 */ public void getMoney1(int n) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } money1 -= n; System.out.println("剩余金额1:" + money1); } /** * 同步 * * @param n * 要取多少钱 */ public void getMoney2(int n) { synchronized (this) {// 锁定this对象,所有属性不可修改 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } money2 -= n; System.out.println("剩余金额2:" + money2); } } /** * 同步 * * @param n * 要取多少钱 */ public synchronized void getMoney(int n) { // 锁定方法,此时不锁定属性, // 所以其它方法仍然可对money进行修改,导致结果出错 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } money -= n; System.out.println("剩余金额:" + money); } } 输出结果: 剩余金额:200 剩余金额1:600 剩余金额:-200 剩余金额2:200 剩余金额1:600 剩余金额2:-200 由结果可知,剩余金额1是错误的结果,因为1没有使用同步(这个结果很随机,但是只有1可能错误)。
五、锁
用来锁定中间的代码。
Lock lc = new ReentrantLock();
lc.lock();
……
lc.unlock();
六、计时器线程
使用方法:创建Timer计时器对象,创建相应任务。调用schedule方法。传入任务,第一次执行延长的时间,以后执行的周期。
Timer timer = new Timer();
EnermyPlaneCreator task = new EnermyPlaneCreator();
timer.schedule(task, 800, 20000);
public class EnermyPlaneCreator extends TimerTask{
public void run() {}
}
七、线程使用模型
1.监听器模型
在A线程中增加标记flag,在B线程中对A中的flag进行操作。B为A的监听线程。
例如:flag初始值为0,表示A没开始执行。当A start之后,将flag赋值为1,这时B就可以知道此时A已经开始执行了。当A执行到某个操作,flag=2,这是B也可以知道A执行到哪里了。
2.生产消费模型
开启一个生产者线程A,一个消费者线程B。
在A中生成对象,在B中消费对象。(例如ArrayList的add,remove操作)
由于线程的执行顺序不确定,这个时候A可能还没有生成,B就去消费了。程序就会有问题。
可以进行判断,当消费的时候判断是否已经有了生成,如果没有生产,就通知生产者进行生产并等待生产者进行生产。
示例代码:
public class Main { // 存放产品对象的队列 static ArrayList<Computer> coms = new ArrayList<Computer>(); public static void main(String[] args) { // 生产者 Produce p = new Produce(); p.start(); // 消费者 Customer c = new Customer(); c.start(); } } public class Computer { String name; public Computer(String name) { this.name = name; } @Override public String toString() {//打印对象时调用 return name; } } public class Produce extends Thread { int i = 0; public void run() { while (true) { try { synchronized (Main.coms) { if (Main.coms.size() > 0) { Main.coms.wait(); } else { Computer com = new Computer("第" + i + "台电脑"); Main.coms.add(com); System.out.println("生产了电脑:" + com); i++; Main.coms.notify(); } } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Customer extends Thread { public void run() { while (true) { try { synchronized (Main.coms) { // 如果产品不够,就等待 if (Main.coms.size() <= 0) { Main.coms.wait(); } else { Computer c = Main.coms.remove(0); System.out.println("-->消费了一台:" + c); Main.coms.notify(); } } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
相关推荐
java多线程总结
C#.net同步异步SOCKET通讯和多线程总结2[参照].pdf
MFC 多线程总结, 开发为于windows的应用程序开发
JAVA多线程总结
这是我总结整理的Java线程总结,希望对大家有所帮助!
C#.net同步异步SOCKET通讯和多线程总结
C++多线程总结[归纳].pdf
C_同步异步SOCKET通讯和多线程总结.doc
Java线程总结.pdf
C# 多线程总结,比较详细和全面,包含多种方式的多线程方法的说明。
【完整课程列表】 1-java_IO(1)(共47页).ppt 1-java_IO(2)(共28页).ppt 2-oracle基础(1)(共48页).ppt 2-oracle基础(2)(共48页).ppt 3-oracle查询和SQL函数(共43页).ppt ...8-IO&线程总结(共7页).ppt
java多线程总结
C#dotnet同步异步SOCKET通讯和多线程总结
Java多线程总结.pdf
线程总结笔记 linux笔记。
C#.net同步异步SOCKET通讯和多线程总结 同步套接字通信 Socket支持下的网上点对点的通信 服务端实现监听连接,客户端实现发送连接请求,建立连接后进行发送和接收数据的功能 服务器端建立一个socket,设置好本机的ip...
不错的线程总结(全面上)1
详细的讲述了多线程的各种用法 Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 ...Java线程:大总结