线程基础—线程的同步

线程的同步,首先要了解一下线程的生命周期。

jdk中用Thread.State枚举来表示线程的几种状态。要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

1.新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态;

2.就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件;

3.运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态,run()方法定义了线程的操作和功能;

4.阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态;

5.死亡:线程完成了它的全部工作或线程被提前强制性地中止。

线程在运行阶段,如果多个线程有共享资源,就会很容易产生同步问题。例如窗口出售车票,如果按照下面线程和客户端写法:

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Window1 implements Runnable{
	int ticket = 100;
	public void run(){
		while(true){
			if(ticket > 0){
				System.out.println(Thread.currentThread().getName()+"售出票号是:"+ ticket--);
			}else{
				break;
			}
		}
	}
}</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class TestWindow1 {
	public static void main(String[] args){
		Window1 w = new Window1();
		Thread t1 =new Thread(w);
		Thread t2 =new Thread(w);
		Thread t3 =new Thread(w);
		
		t1.setName("线程1");
		t2.setName("线程2");
		t3.setName("线程3");
		
		t1.start();
		t2.start();
		t3.start();
	}
}</span>

通过结果可以看出,100号的车票被两个窗口售出肯定是不符合逻辑的。这就出现了线程安全的问题。

问题的原因 :当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。也就是线程1在准备打印车票时此时还未ticket--,而cpu交给了线程2,线程2执行完打印车票打印出100后交给了线程1继续执行,就产生上面这个问题。

java中实现线程的安全,通过通过对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。java中实现线程的安全同步机制主要有两种:

1.同步代码块

<span style="font-family:KaiTi_GB2312;font-size:18px;">	synchronized(同步监视器){
		需要被同步的代码块(即为操作共享数据)
	}</span>
上面的代码我们可以更改为:

class Window2 implements Runnable{
	int ticket = 100; 
	
	public void run(){
		while(true){
//			synchronized(obj){
			synchronized(this){ // this在这里充当锁
				if(ticket > 0){
					try {
						Thread.currentThread().sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"票号为Ϊ:"+ ticket--);

				}
			}
		}
	}
}

2.同步方法

synchronized可以放在方法声明中,表示整个方法为同步方法。例如:

public synchronized void show(String name){
  ....
}

因此上面的方法我们还可以改为:

class Window4 implements Runnable {
	int ticket = 100; 

	public void run() {
		while (true) {
			show();
		}
	}

	public synchronized void show() {
		if (ticket > 0) {
			try {
				Thread.currentThread().sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "售出车票:" + ticket--);
		}
	}
}

这里的共享数据就是多个线程共同操作的同一个数据(变量)

同步监视器是由一个类的对象来充当。哪个线程获取此监视器,谁就执synchronized()方法中被同步的代码,俗称锁。在线程同步中所有的线程必须共用同一把锁,在实现的方式中,考虑同步的话,使用this来充当所,但是在继承的方式中要慎用this。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值