线程基础—线程的同步

来源:互联网 发布:服装零售软件 编辑:程序博客网 时间:2024/05/23 13:16

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

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 blocke.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 blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "售出车票:" + ticket--);}}}

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

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


0 0
原创粉丝点击