首页 > 代码库 > java的线程问题同步与互斥
java的线程问题同步与互斥
以前学过java的线程,但是当时对Tread的理解不是很深,对于里面的同步与互斥,生产者与消费者问题,理解的不够深入,这次又从新学习java的多线程,感觉对线程的理解更加的深入了,觉得有必要写下博客记录下。
本文原创,转载请著明:http://blog.csdn.net/j903829182/article/details/38420503
1.java实现线程的方法;
1.实现Runnable接口,重写run方法,通过Thread的start方法启动线程。这种方法可以实现资源的共享2.继承Thread类,重写run方法
推荐使用Runnable接口实现多线程。
2.线程的状态
创建
开始
就绪
运行
阻塞
终止
3.线程控制的基本方法
isAlive判断线程是否还活着,即线程是否还未终止
getPriority获得线程的优先级数,数值。
setPriority设置线程的优先级数值
Thread.sleep将当前线程睡眠指定毫秒数
join调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。
yield让出cpu,当前线程进入就绪等待调度
wait当前线程进入对象的wait pool
notify/notifyAll唤醒对象的wait pool中的一个/所有等待线程
4.wait和sleep的区别
wait时别的线程可以访问锁定对象,释放cpu的控制权,调用wait方法时必须锁定该对象
sleep时别的线程也不可以访问锁定对象。但可以释放cpu的控制权
5.在执行wait()和notify()之前,必须要先获得互斥锁,即一定要和synchronized一起使用
6.需要注意的是notify()/notifyAll()(唤醒在等待该对象同步锁的线程)调用后,并不是马上就释放对象锁的,
而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM才会在wait()对象锁的线程中随机选取一线程,
赋予其对象锁,唤醒线程,继续执行。
7.以下是我写的线程的一些例子,相信应该能够看懂,我就不多说了,有不理解的可以相互交流,共同进步。
生产者消费者的例子:
package com.wj.demo; /* class Info{ private String name="李新华"; private String content="java讲师"; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } class Producer implements Runnable{ private Info info=null; public Producer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub boolean flag=false; for(int i=0;i<50;i++){ if(flag){ this.info.setName("李兴华"); try { Thread.sleep(90); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.setContent("java讲师"); flag=false; }else{ this.info.setName("baidu"); try { Thread.sleep(90); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.setContent("www.baidu.com"); flag=true; } } } } class Consumer implements Runnable{ private Info info=null; public Consumer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.info.getName()+"--->" +this.info.getContent()); } } } */ /* class Info{ private String name="李新华"; private String content="java讲师"; public synchronized void set(String name,String content){ this.setName(name); try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.setContent(content); } public synchronized void get(){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.getName()+"-->" +this.getContent()); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } class Producer implements Runnable{ private Info info=null; public Producer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub boolean flag=false; for(int i=0;i<50;i++){ if(flag){ this.info.set("李兴华","java讲师"); flag=false; }else{ this.info.set("mldn", "www.mldn.com"); flag=true; } } } } class Consumer implements Runnable{ private Info info=null; public Consumer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.get(); } } } */ /* class Info{ private String name="李新华"; private String content="java讲师"; private boolean flag=false; public synchronized void set(String name,String content){ if(!flag){ try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.setName(name); try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.setContent(content); flag=false; super.notify(); } public synchronized void get(){ if(flag){ try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.getName()+"-->" +this.getContent()); flag=true; super.notify(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } class Producer implements Runnable{ private Info info=null; public Producer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub boolean flag=false; for(int i=0;i<50;i++){ if(flag){ this.info.set("李兴华","java讲师"); flag=false; }else{ this.info.set("mldn", "www.mldn.com"); flag=true; } } } } class Consumer implements Runnable{ private Info info=null; public Consumer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<50;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.get(); } } } */ class Info{ private String name="张三"; //private String content="java讲师"; private boolean flag=false; public synchronized void set(String name){ if(!flag){ try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.setName(name); try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //this.setContent(content); flag=false; super.notify(); } public synchronized void get(){ if(flag){ try { super.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.getName()+"-->" ); flag=true; super.notify(); } public String getName() { return name; } public void setName(String name) { this.name = name; } /*public String getContent() { return content; } public void setContent(String content) { this.content = content; }*/ } class Producer implements Runnable{ private Info info=null; public Producer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub boolean flag=false; for(int i=0;i<20;i++){ if(flag){ this.info.set("张三"); flag=false; }else{ this.info.set("李四"); flag=true; } } } } class Consumer implements Runnable{ private Info info=null; public Consumer(Info info){ this.info=info; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<20;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.info.get(); } } } public class ThreadDemo2 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Info i=new Info(); Producer pro=new Producer(i); Consumer con=new Consumer(i); new Thread(pro).start(); new Thread(con).start(); } }
下面是程序的输出结果:
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
张三-->
李四-->
从运行结果可以看到的是,生产者生产一个,消费者消费一个,进行同步输出
下面是我的写的一个买票的线程例子:
package com.wj.demo; class MyThread1 extends Thread{ private String name; public MyThread1(String name){ this.name=name; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println(name+i); } } } class MyThread2 implements Runnable{ private String name; public MyThread2(String name){ this.name=name; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println(name+i); } } } class MyThread3 implements Runnable{ private int ticket=5; @Override public void run() { // TODO Auto-generated method stub if(ticket>0){ System.out.println("卖票:ticket="+ticket--); } } } class MyThread4 implements Runnable{ @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName()+"运行,i="+i); } } } class MyThread5 implements Runnable{ private String name; private int time; public MyThread5(String name,int time){ this.name=name; this.time=time; } @Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(this.time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(this.name+"线程,休眠"+this.time+"毫秒"); } } class MyThread6 implements Runnable{ private int ticket=110; /*private String name=null; public MyThread6(String name){ this.name=name; }*/ @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<200;i++){ synchronized(this){ if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"卖票:ticket="+ticket--); } } } } } public class ThreadDemo1 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //MyThread1 mt1=new MyThread1("线程A"); //MyThread1 mt2=new MyThread1("线程B"); //mt1.start(); //mt2.start(); /* MyThread2 my1=new MyThread2("线程--A"); MyThread2 my2=new MyThread2("线程--B"); Thread th1=new Thread(my1); Thread th2=new Thread(my2); th1.start(); th2.start();*/ /* MyThread3 my=new MyThread3(); new Thread(my).start(); new Thread(my).start(); new Thread(my).start(); new Thread(my).start(); new Thread(my).start();*/ /* MyThread4 my=new MyThread4(); new Thread(my).start(); new Thread(my,"线程A").start(); new Thread(my,"线程B").start(); new Thread(my).start(); new Thread(my).start();*/ /* MyThread5 my1=new MyThread5("线程A",10000); MyThread5 my2=new MyThread5("线程B",20000); MyThread5 my3=new MyThread5("线程C",30000); MyThread5 my4=new MyThread5("线程D",40000); new Thread(my1).start(); new Thread(my2).start(); new Thread(my3).start(); new Thread(my4).start();*/ MyThread6 mt=new MyThread6(); Thread t1=new Thread(mt,"A"); Thread t2=new Thread(mt,"B"); Thread t3=new Thread(mt,"C"); Thread t4=new Thread(mt,"D"); Thread t5=new Thread(mt,"E"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
程序的运行结果可能如下所示:
B卖票:ticket=110
B卖票:ticket=109
B卖票:ticket=108
B卖票:ticket=107
B卖票:ticket=106
B卖票:ticket=105
B卖票:ticket=104
B卖票:ticket=103
B卖票:ticket=102
B卖票:ticket=101
B卖票:ticket=100
B卖票:ticket=99
E卖票:ticket=98
E卖票:ticket=97
E卖票:ticket=96
E卖票:ticket=95
E卖票:ticket=94
E卖票:ticket=93
E卖票:ticket=92
E卖票:ticket=91
E卖票:ticket=90
E卖票:ticket=89
E卖票:ticket=88
E卖票:ticket=87
E卖票:ticket=86
E卖票:ticket=85
E卖票:ticket=84
E卖票:ticket=83
E卖票:ticket=82
E卖票:ticket=81
E卖票:ticket=80
E卖票:ticket=79
E卖票:ticket=78
E卖票:ticket=77
E卖票:ticket=76
D卖票:ticket=75
D卖票:ticket=74
D卖票:ticket=73
D卖票:ticket=72
C卖票:ticket=71
C卖票:ticket=70
C卖票:ticket=69
C卖票:ticket=68
C卖票:ticket=67
C卖票:ticket=66
C卖票:ticket=65
A卖票:ticket=64
A卖票:ticket=63
A卖票:ticket=62
C卖票:ticket=61
C卖票:ticket=60
C卖票:ticket=59
C卖票:ticket=58
C卖票:ticket=57
C卖票:ticket=56
C卖票:ticket=55
C卖票:ticket=54
C卖票:ticket=53
C卖票:ticket=52
C卖票:ticket=51
C卖票:ticket=50
D卖票:ticket=49
D卖票:ticket=48
D卖票:ticket=47
D卖票:ticket=46
D卖票:ticket=45
D卖票:ticket=44
D卖票:ticket=43
D卖票:ticket=42
D卖票:ticket=41
E卖票:ticket=40
E卖票:ticket=39
E卖票:ticket=38
E卖票:ticket=37
E卖票:ticket=36
E卖票:ticket=35
E卖票:ticket=34
E卖票:ticket=33
E卖票:ticket=32
E卖票:ticket=31
E卖票:ticket=30
E卖票:ticket=29
B卖票:ticket=28
B卖票:ticket=27
B卖票:ticket=26
B卖票:ticket=25
B卖票:ticket=24
B卖票:ticket=23
B卖票:ticket=22
B卖票:ticket=21
B卖票:ticket=20
B卖票:ticket=19
B卖票:ticket=18
B卖票:ticket=17
B卖票:ticket=16
B卖票:ticket=15
B卖票:ticket=14
E卖票:ticket=13
E卖票:ticket=12
D卖票:ticket=11
D卖票:ticket=10
D卖票:ticket=9
D卖票:ticket=8
D卖票:ticket=7
D卖票:ticket=6
D卖票:ticket=5
C卖票:ticket=4
C卖票:ticket=3
C卖票:ticket=2
C卖票:ticket=1
下面的程序展示的是,打印10次A,10次B,10次C,打印的顺序是ABCABCABC.......下面是用线程实现的代码。
代码里面的注释已经很清楚了,我就不再解释了,有问题的,欢迎一起交流,一起进步。
package com.wj.demo; /* * 1.Product类是一个产品类,用来表示生产产品 * 2.里面的有set和get方法,set方法用来设置生产什么样的产品,get是得到产品*/ class Product{ private String name="A";//产品的名字 private boolean flag=true;//标志,true代表可以生产,false代表可以取得产品 //注意:super.wait(),super.notifyAll()这2个方法,一定要是在synchronized所 //包含的代码块里面调用,也就是说只有拥有对象锁的线程,才能有权调用super.wait(),super.notifyAll() //方法,否则会出错。之所以会这样,是因为super.wait()方法是把拥有该对象锁的线程放到等待该对象锁的队列中进行休息 //这个过程需要找到拥有对象锁的线程,所以super.wait()方法应该在synchronized里面的代码块中调用; //同理,super.notifyAll()是用来唤醒在等待该对象锁队列中所有的线程,所以也需要和对象锁有关系,唤醒的是想得到 //该对象锁的所有线程,因此也需要在synchronized代码块中使用。 //synchronized表示只有拥有该对象锁的线程才能进入synchronized代码块,里面。 //综上所述,synchronized,super.wait(),super.notifyAll(),在进行同步控制的时候一般是需要一起配对使用 public synchronized void getName() {//得到产品的函数 if(flag){//如果标志为true,则代表只可以生产,不能进行取产品 try { super.wait();//调用Object父类的方法,使得到该对象锁的线程等待,把该线程放到等待该对象锁的队列里面 //,并且释放cpu,和释放该对象的对象锁,使其他的线程可以得到该对象的锁 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(name);//打印产品的名字 try { Thread.sleep(200);//该线程休眠200毫秒,释放cup,让其他的线程执行,但是不会释放对象锁 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } flag=true;//把标志置位true,表示已经取了产品了,可以进行生产了,已经不没有产品了,不能得到产品了 //调用了super.notifyAll()方法后,并不会马上执行,要等待synchronized代码块所有的程序执行完了以后才会 //释放对象锁,进行唤醒其他的线程 super.notifyAll();//调用父类Object的方法,释放对象锁,唤醒在等待该对象锁的所有线程 } public synchronized void setName(String name) { if(!flag){//如果flag为false则表示,只可以取产品,不能进行生产产品 try { super.wait();//进行等待,和上面的一样 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(200);//解释如上 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.name = name;//设置产品的名字 flag=false;//设置标志,表示可以取产品了,不能再进行生产了 super.notifyAll();//如上所示,唤醒其他的想得到该对象锁的所有线程 } } //Factory类是一个工厂,用来控制生产什么样的产品 class Factory implements Runnable{ private Product product;//共享的对象 public Factory(Product product) {//构造函数,对product进行初始化 super(); this.product = product; } @Override public void run() {//覆写的run方法,进行线程操作 // TODO Auto-generated method stub for(int i=1;i<31;i++){ if(i%3==1){//如果余数为1,则生产A产品 product.setName("A");//生产A产品 }else if(i%3==2){//如果余数为2,则生产B产品 product.setName("B");//生产B产品 }else{//其他的生产C产品 product.setName("C");//生产C产品 } } } } //Customer是消费者类,用来使用工厂生产的产品 class Customer implements Runnable{ private Product product;//贡献资源对象 public Customer(Product product) {//构造函数,初始化product super(); this.product = product; } @Override public void run() { // TODO Auto-generated method stub for(int i=1;i<31;i++){ try { Thread.sleep(500);//进行线程休眠,使打印有时间延迟 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print(""+i+"----->"); this.product.getName();//消费产品 } } } public class ThreadDemo4 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Product p=new Product();//创建共享资源对象 Factory fp=new Factory(p);//创建工厂 Customer cp=new Customer(p);//创建消费者 Thread tfp=new Thread(fp);//创建工厂线程进行生产 Thread tcp=new Thread(cp);//创建消费者线程进行消费 tfp.start();//启动线程 tcp.start();//启动线程 } }
程序的运行结果如下:
1----->A
2----->B
3----->C
4----->A
5----->B
6----->C
7----->A
8----->B
9----->C
10----->A
11----->B
12----->C
13----->A
14----->B
15----->C
16----->A
17----->B
18----->C
19----->A
20----->B
21----->C
22----->A
23----->B
24----->C
25----->A
26----->B
27----->C
28----->A
29----->B
30----->C
到此线程的知识也就基本讲完了,发现对上面的知识进行总结以后,线程也就并没有那么难了,难得就是难于理解什么是多线程,多线程的运行过程。要是理解了多线程的运行过程,那么java中的线程也就没那么可怕了。最后一点就是要举义反三,融汇贯通,利用典型的生产者消费者模式,可以演变后解决很多线程的问题。希望好好理解生产者消费者模式。如果对线程还有什么问题,希望我们可以一起交流。