多线程中的线程同步

 


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

 

                                      线程同步

一.线程之间的同步


 1.什么情况下需要同步
  当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
  如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
 2.同步代码块
  使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
  多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

同步代码块的实例:


 

<span style="font-size:18px;">package cn.itcast.syn;

public class Demo1_Synchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Printer p = new Printer();
		new Thread() {
			public void run() {
				while(true) {
					p.print1();
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					p.print2();
				}
			}
		}.start();
	}

}

class Printer {
	Demo d = new Demo();
	public void print1() {
		synchronized(d){
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
		}
	}
	
	public void print2() {
		synchronized(d) {
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
		}
	}
}

class Demo{}
</span>

 


 

<span style="font-size:18px;">package cn.itcast.syn;

class Ticket extends Thread {
	private static int tick = 100;
	public  void   run(){		
		while(true){
			synchronized(Ticket.class){	
		if (tick<=0){
			System.out.println(getName()+"这是第" + tick-- +"张票");
		  }
		 }
	  }
	}
}
class ticketDemo{
	public static void main(String[] args){
		Ticket t = new Ticket();
		
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}</span>


 3.同步方法
  使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
  非静态同步方法默认使用当前对象this作为锁对象
  静态同步方法是用字节码对象做为锁对象
 4.线程安全问题
  多线程并发操作同一数据时, 就有可能出现线程安全问题
  使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
 5.死锁问题
  多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
  尽量不要嵌套使用

二.线程的方法


 1.yield让出cpu
 2.setPriority()设置线程的优先级


三.线程之间的通信


 1.什么时候需要通信
  多个线程并发执行时, 在默认情况下CPU是随机切换线程的
  如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
 2.怎么通信
  如果希望线程等待, 就调用wait()
  如果希望唤醒等待的线程, 就调用notify();
  这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

3.多个线程通信的问题
  notify()方法是随机唤醒一个线程
notifyAll()方法是唤醒所有线程
  JDK5之前无法唤醒指定的一个线程
  如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件

两条线程之间的等待与唤醒实例:

 


 

<span style="font-size:18px;">package cn.itcast.thread;

public class Demo6_Notify {

	/**
	 * @param args
	 * 等待唤醒机制
	 * sleep()
	 * wait和notify
	 */
	public static void main(String[] args) {
		final Printer p = new Printer();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

}

class Printer {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this){
			if(flag != 1)
				this.wait();				//当前线程等待
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 2;						//flag改为2
			this.notify();				//随机唤醒另一条线程等待的线程
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			if(flag != 2)
				this.wait();					//当前线程等待
			Thread.sleep(1000);
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 1;
			this.notify();				//随机唤醒另一条线程等待的线程
		}
	}
	/*在同步函数或同步代码块中sleep方法和wait方法的区别
	 * 1,sleep方法必须指定参数(时间,可以是毫秒值和纳秒值),当参数的时间执行后,当前自动醒来
	 *   wait方法可以传参数也可以传参数,如果不传参数直接等待,传参数等待指定时间结束后开始等待
	 * 2,sleep方法执行的时候,不释放锁(睡也要抱着锁睡)
	 *   wait方法执行的时候,释放锁
	 * 
	 */
}
</span>

如果存在3条及以上的线程,需要使用notifyAll唤醒所有的线程.

使用notifyAll的实例

 

 

<span style="font-size:18px;">package cn.itcast.thread;

public class Demo7_NotifyAll {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final Printer2 p = new Printer2();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

}

class Printer2 {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this){
			while(flag != 1)
				this.wait();							//当前线程等待
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 2;								//flag改为2
			this.notifyAll();					//随机唤醒另一条线程等待的线程
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			while(flag != 2)
				this.wait();							//线程2等待
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 3;
			this.notifyAll();					//随机唤醒另一条线程等待的线程
		}
	}
	
	public void print3() throws InterruptedException {
		synchronized(this) {
			while(flag != 3)
				this.wait();							//线程3等待
			System.out.print("i");
			System.out.print("t");
			System.out.print("c");
			System.out.print("a");
			System.out.print("s");
			System.out.print("t");
			System.out.print("\r\n");
			flag = 1;
			this.notifyAll();					//随机唤醒另一条线程等待的线程
		}
	}
	
}</span>


 


 

四.JDK5之后的线程控制


 1.同步


  使用ReentrantLock类的lock()和unlock()方法进行同步
 2.通信
  使用ReentrantLock类的newCondition()方法可以获取Condition对象
  需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
  不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

使用互斥锁的实例:

 

<span style="font-size:18px;">package cn.itcast.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo8_ReentrantLock {

	/**
	  * 1.同步
			使用ReentrantLock类的lock()和unlock()方法进行同步
		2.通信
			使用ReentrantLock类的newCondition()方法可以获取Condition对象
			需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
			不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了
	 */
	public static void main(String[] args) {
		final Printer3 p = new Printer3();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

}

class Printer3 {
	private ReentrantLock r = new ReentrantLock();
	private Condition c1 = r.newCondition();
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	private int flag = 1;
	public void print1() throws InterruptedException {
		r.lock();
			if(flag != 1)
				c1.await();							//当前线程等待
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 2;									//flag改为2
			c2.signal();						//随机唤醒另一条线程等待的线程
		r.unlock();
	}
	
	public void print2() throws InterruptedException {
		r.lock();
			if(flag != 2)
				c2.await();						//线程2等待
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 3;
			c3.signal();						//随机唤醒另一条线程等待的线程
		r.unlock();
	}
	
	public void print3() throws InterruptedException {
		r.lock();
			if(flag != 3)
				c3.await();							//线程3等待
			System.out.print("i");
			System.out.print("t");
			System.out.print("c");
			System.out.print("a");
			System.out.print("s");
			System.out.print("t");
			System.out.print("\r\n");
			flag = 1;
			c1.signal();						//随机唤醒另一条线程等待的线程
		r.unlock();
	}
	
}</span>


 



 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值