首页 > 代码库 > 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中的线程也就没那么可怕了。最后一点就是要举义反三,融汇贯通,利用典型的生产者消费者模式,可以演变后解决很多线程的问题。希望好好理解生产者消费者模式。如果对线程还有什么问题,希望我们可以一起交流。