在java程序中,若是有多個線程同時運行,而且同時執行同一段代碼,若是程序每次運行的結果和單線程運行的結果是同樣的,並且其餘變量的值也和預期是同樣的,那麼這段代碼就是線程安全的。java
可是在多線程操做中也可能會有一些線程安全的問題發生。web
以賣票事例做爲說明,有100張票往外售賣,售完結束。安全
public class Tickets implements Runnable{
//初始化票數
private int ticket=100;
public void run() {
//賣票
while (true){
if(ticket>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
}
}
}
}
public class TicketsTest {
public static void main(String[] args) {
//聲明變量
Tickets tickets = new Tickets();
//建立三個線程(窗口)
Thread t1 = new Thread(tickets,"窗口1");
Thread t2 = new Thread(tickets,"窗口2");
Thread t3 = new Thread(tickets,"窗口3");
//三個窗口同時買票
t1.start();
t2.start();
t3.start();
}
}
可是在運行結果中會發生如下這種狀況:票已經賣出,可是總數沒有減小;或者票已經售空,仍然在減票的狀況多線程
窗口3正在賣:100
窗口1正在賣:99
窗口2正在賣:100
窗口1正在賣:98
.......
窗口2正在賣:4
窗口1正在賣:2
窗口3正在賣:1
窗口2正在賣:1
窗口1正在賣:1
這類問題就稱做線程安全問題,爲了解決這個問題,能夠採起一些線程同步的措施併發
當咱們使用多個線程訪問同一資源的時候,且多個線程中對資源有寫的操做,就容易出現線程安全問題。ide
爲了解決併發問題(線程同步問題),也就是多線程併發訪問同一個資源,對這個資源進行寫操做的問題,java中提供了線程同步(synchronized)來解決這個問題。atom
解決線程同步的方法:spa
方法1:同步代碼塊線程
同步代碼塊:synchronized加在代碼塊上,格式以下code
synchronized (lock){
//須要同步的代碼塊
....
}
方法2:同步鎖
對象的同步鎖只是一個概念,能夠想象爲在對象上標記了一個鎖.
鎖對象 能夠是任意類型。
多個線程對象 要使用同一把鎖。
方法3:同步方法
在方法進行同步,格式以下:
public synchronized void method(){
//須要同步的代碼塊
......
}
java.util.concurrent.locks.Lock
機制提供了比synchronized代碼塊和synchronized方法更普遍的鎖定操做,同步代碼塊/同步方法具備的功能Lock都有,除此以外更強大,更體現面向對象。Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,以下:public void lock() :加同步鎖。public void unlock() :釋放同步鎖。使用以下:
public class Tickets implements Runnable{
//初始化票數
private int ticket=100;
Lock lock = new ReentrantLock();
public void run() {
//賣票
while (true){
lock.lock();
if(ticket>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
}
lock.unlock();
}
}
}
在java程序中,若是有多個線程同時運行,而且同時執行同一段代碼,若是程序每次運行的結果和單線程運行的結果是同樣的,並且其餘變量的值也和預期是同樣的,那麼這段代碼就是線程安全的。
可是在多線程操做中也可能會有一些線程安全的問題發生。
以賣票事例做爲說明,有100張票往外售賣,售完結束。
public class Tickets implements Runnable{
//初始化票數
private int ticket=100;
public void run() {
//賣票
while (true){
if(ticket>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
}
}
}
}
public class TicketsTest {
public static void main(String[] args) {
//聲明變量
Tickets tickets = new Tickets();
//建立三個線程(窗口)
Thread t1 = new Thread(tickets,"窗口1");
Thread t2 = new Thread(tickets,"窗口2");
Thread t3 = new Thread(tickets,"窗口3");
//三個窗口同時買票
t1.start();
t2.start();
t3.start();
}
}
可是在運行結果中會發生如下這種狀況:票已經賣出,可是總數沒有減小;或者票已經售空,仍然在減票的狀況
窗口3正在賣:100
窗口1正在賣:99
窗口2正在賣:100
窗口1正在賣:98
.......
窗口2正在賣:4
窗口1正在賣:2
窗口3正在賣:1
窗口2正在賣:1
窗口1正在賣:1
這類問題就稱做線程安全問題,爲了解決這個問題,能夠採起一些線程同步的措施
當咱們使用多個線程訪問同一資源的時候,且多個線程中對資源有寫的操做,就容易出現線程安全問題。
爲了解決併發問題(線程同步問題),也就是多線程併發訪問同一個資源,對這個資源進行寫操做的問題,java中提供了線程同步(synchronized)來解決這個問題。
解決線程同步的方法:
方法1:同步代碼塊
同步代碼塊:synchronized加在代碼塊上,格式以下
synchronized (lock){
//須要同步的代碼塊
....
}
方法2:同步鎖
對象的同步鎖只是一個概念,能夠想象爲在對象上標記了一個鎖.
鎖對象 能夠是任意類型。
多個線程對象 要使用同一把鎖。
方法3:同步方法
在方法進行同步,格式以下:
public synchronized void method(){
//須要同步的代碼塊
......
}
java.util.concurrent.locks.Lock
機制提供了比synchronized代碼塊和synchronized方法更普遍的鎖定操做,同步代碼塊/同步方法具備的功能Lock都有,除此以外更強大,更體現面向對象。Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,以下:public void lock() :加同步鎖。public void unlock() :釋放同步鎖。使用以下:
public class Tickets implements Runnable{
//初始化票數
private int ticket=100;
Lock lock = new ReentrantLock();
public void run() {
//賣票
while (true){
lock.lock();
if(ticket>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在賣:"+ticket--);
}
lock.unlock();
}
}
}