ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程安全与线程状态

2022-01-01 19:06:46  阅读:130  来源: 互联网

标签:状态 synchronized Thread number 安全 线程 static public


 1.线程状态

线程共有有五种状态:新建;就绪;阻塞;运行;死亡

新建状态:通过new Thread()方法创建的新线程状态

就绪状态:通过start()方法启动之后进入就绪状态,并不立即执行,等待CPU调度

阻塞状态:通过sleep()方法或者同步锁使线程自运行状态转换为阻塞状态

运行状态:线程获得CPU调度开始执行

死亡状态:线程执行完毕进入死亡状态

状态转换图为:

join()方法同样可以使线程从运行进入阻塞状态

public class Text {
    public static void main(String[] args) throws InterruptedException {
        RunnableDome runnableDome=new RunnableDome();
        //创建实现类的对象
        Thread thread=new Thread(runnableDome);
        thread.join();
        //将此线程加入当前线程,即main方法所执行的线程执行完毕之后,再执行thread线程
        //将实现类的对象作为参数传入Thread对象
        thread.start();
        
    }
}

sleep()方法代码实现为:

public class TicketThread extends Thread {
    static int number=10;
    static Object obj=new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                try {
                    Thread.sleep(1000);
//使程序进入休眠状态,sleep()方法参数为毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName()+"买到了票"+number);
                    number--;
                }
                else {
                    break;
                }
            }
        }

    }

 2.线程安全

2.1synchronized 关键字(隐式的同步)

引发线程安全的原因主要有两点,一是对共享资源的竟用,二是多条线程共同操作共享资源;synchronized的出现就是为了满足解决此类问题的需求,在java中,sycchronized可以实现在同一时刻,只有一个线程可以执行某个方法或代码块。在此线程进入共享资源后,自动加锁,其余线程在外等待,执行完毕后,自动解锁。这个过程是一个隐式的过程。synchronized的三中应用方式分别为:

 这里先给出买票的一个测试用例,三种应用方式的测试类相同代码实现为:
 


public class Text {
    public static void main(String[] args) {
        TicketThread ticketThread1= new TicketThread();
        ticketThread1.setName("窗口1");
        ticketThread1.start();
        TicketThread ticketThread2=new TicketThread();
        ticketThread2.setName("窗口2");
        ticketThread2.start();
        System.out.println(ticketThread1.getClass()==ticketThread2.getClass());

    }
}

synchronized修饰代码块

指定加锁对象,在线程获取该对象的锁之后,其余线程无法获取,注意此时这个对象应当是唯一的

代码实现:   

public class TicketThread extends Thread {
    static int number=10;
    static Object obj=new Object();
    @Override
    public void run() {
        while (true){
//修饰代码块,且传入的对象(obj)是唯一的
            synchronized (obj){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName()+"买到了票"+number);
                    number--;
                }
                else {
                    break;
                }
            }
}
}

synchronized修饰实例方法 

此时synchronized默认的锁标志即传入的对象为this,注意如果此时有多个线程同时访问时,是允许的,因为各自线程对象的锁时不同的,如若此时访问的是共享资源,那么线程安全则不能被保证

public class TicketThread extends Thread {
    static int number=10;
    static Object obj=new Object();
    @Override
    public void run() {
        ticket();
    }
    /*
            窗口1买到了票10
            窗口2买到了票10
            窗口1买到了票9
            窗口2买到了票8
            窗口1买到了票7
            窗口2买到了票6
            窗口1买到了票5
            窗口2买到了票4
            窗口1买到了票3
            窗口2买到了票2
            窗口1买到了票1
    上述结果的出现就是因为,synchronized修饰成员方法时,锁标志默认的对象是this,每一个线程进去都会加上自己的一把锁,
    这把锁对于其它线程是无效的,因此可能会出现第一个线程进去,还未做number--操作时时,第二个线程进去

     */

    public synchronized  void ticket() {
        while(true){
            if(number>0){
                System.out.println(Thread.currentThread().getName()+"买到了票"+number);
                number--;
            }
            else break;
        }
    }
}

synchronized修饰静态方法 

注意此时与修饰成员方法不同的点是此时synchronized锁标志即传入的对象为:class对象,此时即使是多个线程访问这一共享资源,也是线程安全的;因为在同一个类中,多个线程的class对象是相同的,即所加的锁对所有线程都有效,System.out.println(ticketThread1.getClass()==ticketThread2.getClass());// 可用此语句判断两个线程对应的Class对象是否相同;

代码实现:

public class TicketThread extends Thread {
    static int number=10;
    static Object obj=new Object();
    @Override
    public void run() {
       
        ticket();
    }
    
   /*
    修饰静态方法时则不会出现此类情况,原因是修饰静态方法时,锁标志的对象默认为对应的Class对象,只要两个线程对象是
    同一个类的对象,则对应的Class对象相同,System.out.println(ticketThread1.getClass()==ticketThread2.getClass());
    可用此语句判断两个线程对应的Class对象是否相同
    则这把锁对两个线程都有作用,当一个线程进去时,锁关闭,另一个线程则在阻塞状态。
    */

    public synchronized  void ticket() {
        while(true){
            if(number>0){
                System.out.println(Thread.currentThread().getName()+"买到了票"+number);
                number--;
            }
            else break;
        }
    }
}

2.2 Lock(显式的)

Lock主要是通过Lock接口的实现类ReentrantLock来实现线程安全;与synchronized关键字的不同是需要手动关闭与释放锁,加锁的方法为lock();释放的方法为unlock();注意在发生异常时,不会自动释放锁,因此一般来说,使用Lock必须在try{}catch{}块中进行,且释放锁必须放在finally块中进行,确保所以定被释放,防治死锁的出现

代码实现为:

import javax.swing.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentantLockDome extends Thread {
    static int number = 10;
    static Lock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();//加锁,使代码快进入锁定状态,其余的线程排队等候
                Thread.sleep(50);
                if (number > 0) {
                    System.out.println(Thread.currentThread().getName() + "买到了票" + number);
                    number--;
                }else {
                    Thread.currentThread().stop();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                lock.unlock();
            }
        }
    }

}

测试类为 :

import synchronzied.TicketThread;

public class Text {
    public static void main(String[] args) {
        ReentantLockDome r1=new ReentantLockDome();
        ReentantLockDome r2=new ReentantLockDome();
        r1.setName("窗口1");
        r2.setName("窗口2");
        r1.start();
        r2.start();
    }
}

标签:状态,synchronized,Thread,number,安全,线程,static,public
来源: https://blog.csdn.net/qq_51913153/article/details/122269784

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有