线程安全

Posted wuhao-0206

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全相关的知识,希望对你有一定的参考价值。

1、线程安全:多线程单线程程序运行结果一致
      线程不安全:多线程单线程程序运行结果不一致
2、导致线程安全问题原因
全局变量或者静态变量引起;
一般情况下,多个线程只读数据,不写数据,则线程是安全的;
若多个线程同时执行写操作,则容易导致线程不安全问题发生。
根本原因:
多个线程操作共享的数据
操作共享数据的线程代码有多条
多个线程对共享数据有写操作
3、线程安全演示
单线程情况:
package com.wuhao.thread;

/**
 * 线程安全演示
 */
public class Ticket implements Runnable {
    private Integer ticketNum = 100;//电影票张数
    @Override
    public void run() {
        while (true){
            if (ticketNum>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String name = Thread.currentThread().getName();
                System.out.println("线程"+name+"销售电影票:"+ticketNum--);
            }


        }
    }
}


package com.wuhao.thread;

public class TicketSafeTest {
    public static void main(String[] args) {
        //1、创建电影票对象
        Ticket ticket = new Ticket();
        //2、创建Thread,执行电影票售卖
        Thread thread = new Thread(ticket,"窗口一");
        Thread thread1 = new Thread(ticket,"窗口二");
        Thread thread2= new Thread(ticket,"窗口三");
        thread.start();
        thread1.start();
        thread2.start();
    }
}


"C:Program FilesJavajdk1.8.0_131injava.exe" "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5libidea_rt.jar=56766:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_131jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_131jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_131jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_131jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_131jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_131jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_131jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_131jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_131jrelibext
ashorn.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_131jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_131jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_131jrelibjce.jar;C:Program FilesJavajdk1.8.0_131jrelibjfr.jar;C:Program FilesJavajdk1.8.0_131jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_131jrelibjsse.jar;C:Program FilesJavajdk1.8.0_131jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_131jrelibplugin.jar;C:Program FilesJavajdk1.8.0_131jrelib
esources.jar;C:Program FilesJavajdk1.8.0_131jrelib
t.jar;C:UsersAdministratorIdeaProjectsmultiThread	hread_safety	argetclasses" com.wuhao.thread.TicketSafeTest
线程窗口二销售电影票:100
线程窗口三销售电影票:99
线程窗口一销售电影票:100
线程窗口三销售电影票:98
线程窗口二销售电影票:97
线程窗口一销售电影票:98
线程窗口二销售电影票:96
线程窗口一销售电影票:95
线程窗口三销售电影票:95
线程窗口三销售电影票:94
线程窗口二销售电影票:93
线程窗口一销售电影票:92
线程窗口一销售电影票:91
线程窗口二销售电影票:90
线程窗口三销售电影票:89
线程窗口一销售电影票:88
线程窗口三销售电影票:88
线程窗口二销售电影票:88
线程窗口一销售电影票:87
线程窗口二销售电影票:87
线程窗口三销售电影票:87
线程窗口一销售电影票:86
线程窗口二销售电影票:86
线程窗口三销售电影票:86
线程窗口一销售电影票:85
线程窗口三销售电影票:85
线程窗口二销售电影票:85
线程窗口一销售电影票:84
线程窗口二销售电影票:84
线程窗口三销售电影票:84
线程窗口一销售电影票:83
线程窗口二销售电影票:82
线程窗口三销售电影票:81
线程窗口二销售电影票:80
线程窗口三销售电影票:80
线程窗口一销售电影票:80
线程窗口三销售电影票:79
线程窗口一销售电影票:77
线程窗口二销售电影票:78
线程窗口一销售电影票:76
线程窗口三销售电影票:76
线程窗口二销售电影票:76
线程窗口二销售电影票:75
线程窗口三销售电影票:75
线程窗口一销售电影票:75
线程窗口三销售电影票:74
线程窗口一销售电影票:74
线程窗口二销售电影票:74
线程窗口二销售电影票:73
线程窗口三销售电影票:73
线程窗口一销售电影票:73
线程窗口三销售电影票:72
线程窗口二销售电影票:72
线程窗口一销售电影票:72
线程窗口三销售电影票:71
线程窗口一销售电影票:71
线程窗口二销售电影票:71
线程窗口二销售电影票:70
线程窗口一销售电影票:70
线程窗口三销售电影票:70
线程窗口二销售电影票:69
线程窗口三销售电影票:69
线程窗口一销售电影票:69
线程窗口一销售电影票:68
线程窗口三销售电影票:68
线程窗口二销售电影票:68
线程窗口一销售电影票:67
线程窗口二销售电影票:66
线程窗口三销售电影票:66
线程窗口三销售电影票:65
线程窗口二销售电影票:64
线程窗口一销售电影票:65
线程窗口二销售电影票:63
线程窗口一销售电影票:63
线程窗口三销售电影票:63
线程窗口二销售电影票:62
线程窗口三销售电影票:62
线程窗口一销售电影票:62
线程窗口一销售电影票:61
线程窗口三销售电影票:61
线程窗口二销售电影票:60
线程窗口一销售电影票:59
线程窗口二销售电影票:58
线程窗口三销售电影票:58
线程窗口一销售电影票:57
线程窗口二销售电影票:57
线程窗口三销售电影票:57
线程窗口二销售电影票:56
线程窗口三销售电影票:55
线程窗口一销售电影票:56
线程窗口三销售电影票:54
线程窗口一销售电影票:54
线程窗口二销售电影票:54
线程窗口一销售电影票:53
线程窗口三销售电影票:52
线程窗口二销售电影票:53
线程窗口二销售电影票:51
线程窗口一销售电影票:51
线程窗口三销售电影票:50
线程窗口一销售电影票:49
线程窗口三销售电影票:49
线程窗口二销售电影票:49
线程窗口一销售电影票:48
线程窗口二销售电影票:47
线程窗口三销售电影票:48
线程窗口二销售电影票:46
线程窗口一销售电影票:46
线程窗口三销售电影票:46
线程窗口一销售电影票:45
线程窗口二销售电影票:44
线程窗口三销售电影票:43
线程窗口三销售电影票:42
线程窗口一销售电影票:42
线程窗口二销售电影票:42
线程窗口二销售电影票:41
线程窗口一销售电影票:41
线程窗口三销售电影票:41
线程窗口三销售电影票:40
线程窗口一销售电影票:40
线程窗口二销售电影票:39
线程窗口一销售电影票:38
线程窗口三销售电影票:38
线程窗口二销售电影票:38
线程窗口一销售电影票:37
线程窗口二销售电影票:37
线程窗口三销售电影票:37
线程窗口二销售电影票:36
线程窗口三销售电影票:36
线程窗口一销售电影票:36
线程窗口三销售电影票:35
线程窗口二销售电影票:34
线程窗口一销售电影票:35
线程窗口一销售电影票:33
线程窗口三销售电影票:31
线程窗口二销售电影票:32
线程窗口一销售电影票:30
线程窗口三销售电影票:30
线程窗口二销售电影票:30
线程窗口三销售电影票:29
线程窗口二销售电影票:29
线程窗口一销售电影票:29
线程窗口一销售电影票:28
线程窗口二销售电影票:27
线程窗口三销售电影票:28
线程窗口一销售电影票:26
线程窗口二销售电影票:26
线程窗口三销售电影票:26
线程窗口一销售电影票:25
线程窗口三销售电影票:25
线程窗口二销售电影票:25
线程窗口一销售电影票:24
线程窗口三销售电影票:23
线程窗口二销售电影票:24
线程窗口一销售电影票:22
线程窗口二销售电影票:21
线程窗口三销售电影票:22
线程窗口一销售电影票:18
线程窗口二销售电影票:20
线程窗口三销售电影票:19
线程窗口三销售电影票:17
线程窗口二销售电影票:17
线程窗口一销售电影票:17
线程窗口二销售电影票:16
线程窗口一销售电影票:16
线程窗口三销售电影票:16
线程窗口二销售电影票:15
线程窗口三销售电影票:15
线程窗口一销售电影票:14
线程窗口一销售电影票:13
线程窗口二销售电影票:13
线程窗口三销售电影票:13
线程窗口一销售电影票:12
线程窗口二销售电影票:12
线程窗口三销售电影票:12
线程窗口二销售电影票:11
线程窗口三销售电影票:11
线程窗口一销售电影票:11
线程窗口三销售电影票:10
线程窗口二销售电影票:10
线程窗口一销售电影票:10
线程窗口三销售电影票:9
线程窗口一销售电影票:9
线程窗口二销售电影票:8
线程窗口三销售电影票:7
线程窗口一销售电影票:7
线程窗口二销售电影票:7
线程窗口三销售电影票:6
线程窗口一销售电影票:5
线程窗口二销售电影票:6
线程窗口三销售电影票:4
线程窗口一销售电影票:4
线程窗口二销售电影票:4
线程窗口一销售电影票:3
线程窗口三销售电影票:3
线程窗口二销售电影票:3
线程窗口三销售电影票:2
线程窗口二销售电影票:2
线程窗口一销售电影票:2
线程窗口一销售电影票:1
线程窗口二销售电影票:1
线程窗口三销售电影票:1


4、线程安全问题解决
同步代码块 synchronized
同步方法  synchronized
同步锁 ReentrantLock
特殊域变量 volatile
局部变量 ThreadLocal
阻塞队列 LinkedBlockingQuene
原子变量 Atomic*
同步代码块:
package com.wuhao.thread;

/**
 * 线程安全演示
 */
public class Ticket implements Runnable {
    private Integer ticketNum = 100;//电影票张数
    private Object object = new Object();
    @Override
    public void run() {
        while (true){
            synchronized(object){
                if (ticketNum>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    System.out.println("线程"+name+"销售电影票:"+ticketNum--);
                }
            }



        }
    }
}


package com.wuhao.thread;

public class TicketSafeTest {
    public static void main(String[] args) {
        //1、创建电影票对象
        Ticket ticket = new Ticket();
        //2、创建Thread,执行电影票售卖
        Thread thread = new Thread(ticket,"窗口一");
        Thread thread1 = new Thread(ticket,"窗口二");
        Thread thread2= new Thread(ticket,"窗口三");
        thread.start();
        thread1.start();
        thread2.start();
    }
}


"C:Program FilesJavajdk1.8.0_131injava.exe" "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5libidea_rt.jar=56925:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_131jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_131jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_131jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_131jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_131jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_131jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_131jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_131jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_131jrelibext
ashorn.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_131jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_131jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_131jrelibjce.jar;C:Program FilesJavajdk1.8.0_131jrelibjfr.jar;C:Program FilesJavajdk1.8.0_131jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_131jrelibjsse.jar;C:Program FilesJavajdk1.8.0_131jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_131jrelibplugin.jar;C:Program FilesJavajdk1.8.0_131jrelib
esources.jar;C:Program FilesJavajdk1.8.0_131jrelib
t.jar;C:UsersAdministratorIdeaProjectsmultiThread	hread_safety	argetclasses" com.wuhao.thread.TicketSafeTest
线程窗口一销售电影票:100
线程窗口一销售电影票:99
线程窗口一销售电影票:98
线程窗口一销售电影票:97
线程窗口一销售电影票:96
线程窗口三销售电影票:95
线程窗口三销售电影票:94
线程窗口二销售电影票:93
线程窗口二销售电影票:92
线程窗口二销售电影票:91
线程窗口二销售电影票:90
线程窗口二销售电影票:89
线程窗口二销售电影票:88
线程窗口二销售电影票:87
线程窗口二销售电影票:86
线程窗口三销售电影票:85
线程窗口三销售电影票:84
线程窗口三销售电影票:83
线程窗口三销售电影票:82
线程窗口三销售电影票:81
线程窗口三销售电影票:80
线程窗口三销售电影票:79
线程窗口三销售电影票:78
线程窗口三销售电影票:77
线程窗口三销售电影票:76
线程窗口三销售电影票:75
线程窗口三销售电影票:74
线程窗口三销售电影票:73
线程窗口三销售电影票:72
线程窗口三销售电影票:71
线程窗口三销售电影票:70
线程窗口三销售电影票:69
线程窗口三销售电影票:68
线程窗口三销售电影票:67
线程窗口三销售电影票:66
线程窗口三销售电影票:65
线程窗口三销售电影票:64
线程窗口三销售电影票:63
线程窗口三销售电影票:62
线程窗口三销售电影票:61
线程窗口三销售电影票:60
线程窗口三销售电影票:59
线程窗口三销售电影票:58
线程窗口三销售电影票:57
线程窗口三销售电影票:56
线程窗口三销售电影票:55
线程窗口三销售电影票:54
线程窗口三销售电影票:53
线程窗口三销售电影票:52
线程窗口三销售电影票:51
线程窗口三销售电影票:50
线程窗口三销售电影票:49
线程窗口三销售电影票:48
线程窗口三销售电影票:47
线程窗口三销售电影票:46
线程窗口三销售电影票:45
线程窗口三销售电影票:44
线程窗口三销售电影票:43
线程窗口三销售电影票:42
线程窗口三销售电影票:41
线程窗口一销售电影票:40
线程窗口一销售电影票:39
线程窗口一销售电影票:38
线程窗口一销售电影票:37
线程窗口一销售电影票:36
线程窗口一销售电影票:35
线程窗口一销售电影票:34
线程窗口一销售电影票:33
线程窗口一销售电影票:32
线程窗口一销售电影票:31
线程窗口一销售电影票:30
线程窗口一销售电影票:29
线程窗口一销售电影票:28
线程窗口一销售电影票:27
线程窗口一销售电影票:26
线程窗口一销售电影票:25
线程窗口一销售电影票:24
线程窗口一销售电影票:23
线程窗口一销售电影票:22
线程窗口一销售电影票:21
线程窗口一销售电影票:20
线程窗口一销售电影票:19
线程窗口一销售电影票:18
线程窗口一销售电影票:17
线程窗口一销售电影票:16
线程窗口一销售电影票:15
线程窗口一销售电影票:14
线程窗口一销售电影票:13
线程窗口一销售电影票:12
线程窗口一销售电影票:11
线程窗口一销售电影票:10
线程窗口一销售电影票:9
线程窗口一销售电影票:8
线程窗口一销售电影票:7
线程窗口一销售电影票:6
线程窗口一销售电影票:5
线程窗口一销售电影票:4
线程窗口一销售电影票:3
线程窗口一销售电影票:2
线程窗口一销售电影票:1


同步方法:
package com.wuhao.thread;

/**
 * 线程安全演示
 */
public class Ticket implements Runnable {
    private Integer ticketNum = 100;//电影票张数
    private Object object = new Object();
    @Override
    public void run() {
        while (true){
            saleTicket();
        }
    }
    private  synchronized void saleTicket(){
        if (ticketNum>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String name = Thread.currentThread().getName();
            System.out.println("线程"+name+"销售电影票:"+ticketNum--);
        }
    }
}


package com.wuhao.thread;

public class TicketSafeTest {
    public static void main(String[] args) {
        //1、创建电影票对象
        Ticket ticket = new Ticket();
        //2、创建Thread,执行电影票售卖
        Thread thread = new Thread(ticket,"窗口一");
        Thread thread1 = new Thread(ticket,"窗口二");
        Thread thread2= new Thread(ticket,"窗口三");
        thread.start();
        thread1.start();
        thread2.start();
    }
}


"C:Program FilesJavajdk1.8.0_131injava.exe" "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5libidea_rt.jar=56973:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_131jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_131jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_131jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_131jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_131jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_131jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_131jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_131jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_131jrelibext
ashorn.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_131jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_131jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_131jrelibjce.jar;C:Program FilesJavajdk1.8.0_131jrelibjfr.jar;C:Program FilesJavajdk1.8.0_131jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_131jrelibjsse.jar;C:Program FilesJavajdk1.8.0_131jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_131jrelibplugin.jar;C:Program FilesJavajdk1.8.0_131jrelib
esources.jar;C:Program FilesJavajdk1.8.0_131jrelib
t.jar;C:UsersAdministratorIdeaProjectsmultiThread	hread_safety	argetclasses" com.wuhao.thread.TicketSafeTest
线程窗口二销售电影票:100
线程窗口二销售电影票:99
线程窗口二销售电影票:98
线程窗口二销售电影票:97
线程窗口二销售电影票:96
线程窗口二销售电影票:95
线程窗口二销售电影票:94
线程窗口二销售电影票:93
线程窗口二销售电影票:92
线程窗口二销售电影票:91
线程窗口二销售电影票:90
线程窗口二销售电影票:89
线程窗口二销售电影票:88
线程窗口二销售电影票:87
线程窗口二销售电影票:86
线程窗口二销售电影票:85
线程窗口二销售电影票:84
线程窗口二销售电影票:83
线程窗口二销售电影票:82
线程窗口二销售电影票:81
线程窗口二销售电影票:80
线程窗口二销售电影票:79
线程窗口二销售电影票:78
线程窗口二销售电影票:77
线程窗口二销售电影票:76
线程窗口二销售电影票:75
线程窗口二销售电影票:74
线程窗口二销售电影票:73
线程窗口一销售电影票:72
线程窗口一销售电影票:71
线程窗口一销售电影票:70
线程窗口一销售电影票:69
线程窗口三销售电影票:68
线程窗口三销售电影票:67
线程窗口三销售电影票:66
线程窗口三销售电影票:65
线程窗口三销售电影票:64
线程窗口一销售电影票:63
线程窗口一销售电影票:62
线程窗口一销售电影票:61
线程窗口一销售电影票:60
线程窗口一销售电影票:59
线程窗口一销售电影票:58
线程窗口一销售电影票:57
线程窗口一销售电影票:56
线程窗口二销售电影票:55
线程窗口一销售电影票:54
线程窗口一销售电影票:53
线程窗口一销售电影票:52
线程窗口一销售电影票:51
线程窗口一销售电影票:50
线程窗口一销售电影票:49
线程窗口三销售电影票:48
线程窗口三销售电影票:47
线程窗口三销售电影票:46
线程窗口三销售电影票:45
线程窗口三销售电影票:44
线程窗口一销售电影票:43
线程窗口一销售电影票:42
线程窗口一销售电影票:41
线程窗口二销售电影票:40
线程窗口一销售电影票:39
线程窗口一销售电影票:38
线程窗口一销售电影票:37
线程窗口一销售电影票:36
线程窗口三销售电影票:35
线程窗口一销售电影票:34
线程窗口一销售电影票:33
线程窗口二销售电影票:32
线程窗口一销售电影票:31
线程窗口一销售电影票:30
线程窗口三销售电影票:29
线程窗口三销售电影票:28
线程窗口三销售电影票:27
线程窗口三销售电影票:26
线程窗口一销售电影票:25
线程窗口二销售电影票:24
线程窗口二销售电影票:23
线程窗口一销售电影票:22
线程窗口一销售电影票:21
线程窗口一销售电影票:20
线程窗口一销售电影票:19
线程窗口三销售电影票:18
线程窗口三销售电影票:17
线程窗口三销售电影票:16
线程窗口三销售电影票:15
线程窗口三销售电影票:14
线程窗口一销售电影票:13
线程窗口二销售电影票:12
线程窗口二销售电影票:11
线程窗口二销售电影票:10
线程窗口二销售电影票:9
线程窗口二销售电影票:8
线程窗口二销售电影票:7
线程窗口一销售电影票:6
线程窗口一销售电影票:5
线程窗口三销售电影票:4
线程窗口一销售电影票:3
线程窗口一销售电影票:2
线程窗口一销售电影票:1


同步锁:
公平锁:各个线程有公平竞争锁的机会
独占锁:非公平锁,不是所有线程都有获得锁的机会
重入锁:线程再次请求锁的时候就能获得锁,则成锁为重入锁
注意:使用同步锁的时候,加锁必须伴随解锁,不然容易发生死锁,解锁过程用try代码块finally里书写
package com.wuhao.thread;

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

/**
 * 线程安全演示
 */
public class Ticket implements Runnable {
    private Integer ticketNum = 100;//电影票张数
    private Object object = new Object();
    private Lock lock = new ReentrantLock(true);//参数:是否为公平锁,true则为公平锁,公平锁意味着各个线程都有竞争锁的权利,false则是非公平锁,即为独占锁。
    @Override
    public void run() {
        while (true){
            lock.lock();//lock加锁
            try {
                if (ticketNum>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    System.out.println("线程"+name+"销售电影票:"+ticketNum--);
                }
            }finally {
                lock.unlock();//解锁
            }

        }
    }
    private  synchronized void saleTicket(){

    }
}


package com.wuhao.thread;

public class TicketSafeTest {
    public static void main(String[] args) {
        //1、创建电影票对象
        Ticket ticket = new Ticket();
        //2、创建Thread,执行电影票售卖
        Thread thread = new Thread(ticket,"窗口一");
        Thread thread1 = new Thread(ticket,"窗口二");
        Thread thread2= new Thread(ticket,"窗口三");
        thread.start();
        thread1.start();
        thread2.start();
    }
}


"C:Program FilesJavajdk1.8.0_131injava.exe" "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5libidea_rt.jar=58855:C:Program FilesJetBrainsIntelliJ IDEA 2018.2.5in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_131jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_131jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_131jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_131jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_131jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_131jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_131jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_131jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_131jrelibext
ashorn.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_131jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_131jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_131jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_131jrelibjce.jar;C:Program FilesJavajdk1.8.0_131jrelibjfr.jar;C:Program FilesJavajdk1.8.0_131jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_131jrelibjsse.jar;C:Program FilesJavajdk1.8.0_131jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_131jrelibplugin.jar;C:Program FilesJavajdk1.8.0_131jrelib
esources.jar;C:Program FilesJavajdk1.8.0_131jrelib
t.jar;C:UsersAdministratorIdeaProjectsmultiThread	hread_safety	argetclasses" com.wuhao.thread.TicketSafeTest
线程窗口二销售电影票:100
线程窗口三销售电影票:99
线程窗口一销售电影票:98
线程窗口二销售电影票:97
线程窗口三销售电影票:96
线程窗口一销售电影票:95
线程窗口二销售电影票:94
线程窗口三销售电影票:93
线程窗口一销售电影票:92
线程窗口二销售电影票:91
线程窗口三销售电影票:90
线程窗口一销售电影票:89
线程窗口二销售电影票:88
线程窗口三销售电影票:87
线程窗口一销售电影票:86
线程窗口二销售电影票:85
线程窗口三销售电影票:84
线程窗口一销售电影票:83
线程窗口二销售电影票:82
线程窗口三销售电影票:81
线程窗口一销售电影票:80
线程窗口二销售电影票:79
线程窗口三销售电影票:78
线程窗口一销售电影票:77
线程窗口二销售电影票:76
线程窗口三销售电影票:75
线程窗口一销售电影票:74
线程窗口二销售电影票:73
线程窗口三销售电影票:72
线程窗口一销售电影票:71
线程窗口二销售电影票:70
线程窗口三销售电影票:69
线程窗口一销售电影票:68
线程窗口二销售电影票:67
线程窗口三销售电影票:66
线程窗口一销售电影票:65
线程窗口二销售电影票:64
线程窗口三销售电影票:63
线程窗口一销售电影票:62
线程窗口二销售电影票:61
线程窗口三销售电影票:60
线程窗口一销售电影票:59
线程窗口二销售电影票:58
线程窗口三销售电影票:57
线程窗口一销售电影票:56
线程窗口二销售电影票:55
线程窗口三销售电影票:54
线程窗口一销售电影票:53
线程窗口二销售电影票:52
线程窗口三销售电影票:51
线程窗口一销售电影票:50
线程窗口二销售电影票:49
线程窗口三销售电影票:48
线程窗口一销售电影票:47
线程窗口二销售电影票:46
线程窗口三销售电影票:45
线程窗口一销售电影票:44
线程窗口二销售电影票:43
线程窗口三销售电影票:42
线程窗口一销售电影票:41
线程窗口二销售电影票:40
线程窗口三销售电影票:39
线程窗口一销售电影票:38
线程窗口二销售电影票:37
线程窗口三销售电影票:36
线程窗口一销售电影票:35
线程窗口二销售电影票:34
线程窗口三销售电影票:33
线程窗口一销售电影票:32
线程窗口二销售电影票:31
线程窗口三销售电影票:30
线程窗口一销售电影票:29
线程窗口二销售电影票:28
线程窗口三销售电影票:27
线程窗口一销售电影票:26
线程窗口二销售电影票:25
线程窗口三销售电影票:24
线程窗口一销售电影票:23
线程窗口二销售电影票:22
线程窗口三销售电影票:21
线程窗口一销售电影票:20
线程窗口二销售电影票:19
线程窗口三销售电影票:18
线程窗口一销售电影票:17
线程窗口二销售电影票:16
线程窗口三销售电影票:15
线程窗口一销售电影票:14
线程窗口二销售电影票:13
线程窗口三销售电影票:12
线程窗口一销售电影票:11
线程窗口二销售电影票:10
线程窗口三销售电影票:9
线程窗口一销售电影票:8
线程窗口二销售电影票:7
线程窗口三销售电影票:6
线程窗口一销售电影票:5
线程窗口二销售电影票:4
线程窗口三销售电影票:3
线程窗口一销售电影票:2
线程窗口二销售电影票:1


总结:
synchronized是java内置关键字,在jvm层面,lock是个java类
synchronized无法判断是否获取锁的状态,lock可以判断是否获得锁
synchronized会自动释放锁,lock必须在finally代码块里释放锁,unlock()方法释放锁,否则容易造成死锁
synchronized的线程1和2,如果1获得锁,则2线程等待,如果线程1阻塞,线程2则一直等待,而Lock锁则不会,如果尝试获取不到锁,线程可以不用一直等待就结束
synchronized锁可重入,不可中断,非公平,而Lock锁可重入,可中断,可公平
Lock锁适合大量同步的代码同步问题,synchronized锁适合代码量少的同步

 

以上是关于线程安全的主要内容,如果未能解决你的问题,请参考以下文章

HashMap 和 ConcurrentHashMap 的区别

线程同步-使用ReaderWriterLockSlim类

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

多线程 Thread 线程同步 synchronized

活动到片段方法调用带有进度条的线程

第十次总结 线程的异步和同步