線程
- 線程的三種狀態(tài)(五種狀態(tài))
- 運行態(tài)(Running) ---> yield() ---> 就緒態(tài)
- 就緒態(tài)(Runnable)
- 阻塞態(tài)(Blocked)
sleep( ) / IO中斷 / join( )
wait( ) ---> 等待池 ---> notify( ) / notifyAll( ) ---> 等待池
synchronized ---> 等鎖池 ---> 搶鎖池 ---> 就緒態(tài)
- Thread類有兩個靜態(tài)方法可以讓正在執(zhí)行的線程放棄對cup的占用
1.sleep - 讓CPU的時候不考慮優(yōu)先級司浪,yield要考慮優(yōu)先級起暮。
2.yield - 讓出CPU后進入就緒態(tài)包吝,sleep讓出CPU后進入阻塞態(tài)
public class Frame extends JFrame implements ActionListener{
private JButton aButton,bButton,cButton,dButton;
private Thread thread1,thread2;
public static final int Width = 80;
public static final int Height = 50;
public Frame(){
this.setSize(500,300);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null);
aButton = new JButton("上傳");
aButton.setBounds(20, 150, Width, Height);
bButton = new JButton("下載");
bButton.setBounds(140, 150, Width, Height);
cButton = new JButton("計算");
cButton.setBounds(260, 150, Width, Height);
cButton.setEnabled(false);//一開始禁用"計算"按鈕
dButton = new JButton("關(guān)于");
dButton.setBounds(380, 150, Width, Height);
aButton.addActionListener(this);
bButton.addActionListener(this);
cButton.addActionListener(this);
dButton.addActionListener(this);
this.add(aButton);
this.add(bButton);
this.add(cButton);
this.add(dButton);
}
private void download(){
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void upload(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Frame().setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("上傳")) {
aButton.setEnabled(false);
aButton.setText("上傳中");
thread1= new Thread(()->{
upload();
aButton.setEnabled(true);
aButton.setText("上傳");
});
thread1.start();
}
else if (command.equals("下載")) {
bButton.setEnabled(false);
bButton.setText("下載中");
thread2 = new Thread(new Runnable() {
@Override
public void run() {
download();
bButton.setEnabled(true);
bButton.setText("下載");
}
});
thread2.start();
}
else if (command.equals("計算")) {
}
else if (command.equals("關(guān)于")) {
JOptionPane.showMessageDialog(null, "load.....");
}
new Thread(() -> {
if (thread1 != null && thread2 != null) {
try {
thread1.join();
thread2.join();
cButton.setEnabled(true);
}
catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}).start();
}
}
線程同步
synchronized(隱式鎖機制)有兩種用法:
1.放在方法的前面,該方法值允許搶占到對象鎖的線程進入執(zhí)行
2.構(gòu)造synchronized代碼塊(同步代碼塊)始锚,只允許搶占到對象鎖的線程進入執(zhí)行Lock(顯示鎖機制)
private Lock lock = new ReentrantLock();
lock.lock();
.....
lock.unlock();
沒有搶占到對象鎖的線程在系統(tǒng)自動維護的等鎖池中等待
如果搶到鎖的線程釋放了對象鎖,那么這些等鎖的線程就搶鎖岁诉,誰搶到鎖誰就進入同步代碼塊中執(zhí)行娩贷,沒有搶到的繼續(xù)等待
基于synchronized關(guān)鍵字的鎖機制是可重入的鎖機制join方法是一個阻塞式方法,表示等待線程結(jié)束
如果將join方法放到主線程碱茁,會導(dǎo)致其他線程被阻塞
package org.mobiletrain;
//import java.util.ArrayList;
//import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//線程同步問題
class BankAccount {
private double balance;
private Lock lock = new ReentrantLock();
public double getBalance() {
return balance;
}
//使用Java 5 以后的鎖機制解決同步問題
public /*synchronized*/ void transfer(double money){
lock.lock();
System.out.println(Thread.currentThread().getName());
double newBalance = balance + money;
try {
Thread.sleep(1);
}
catch (InterruptedException e) {
}
balance = newBalance;
lock.unlock();
}
}
class AddMoneyHandler implements Runnable{
private BankAccount account;
private int money;
public AddMoneyHandler(BankAccount account,int money) {
this.account = account;
this.money = money;
}
@Override
public void run() {
//synchronized (account) {
account.transfer(money);
//}
}
}
public class Test01 {
public static void main(String[] args) throws InterruptedException {
//List<Thread> list = new ArrayList<>();
ExecutorService service = Executors.newFixedThreadPool(10);
BankAccount mainAccount = new BankAccount();
for (int i = 0; i < 100; i++){
service.execute(new AddMoneyHandler(mainAccount, 100));
//Thread t = new Thread(new AddMoneyHandler(mainAccount, 100));
//list.add(t);
//t.start();
}
service.shutdown();
//判斷線程池里的線程有沒有終止
while ( ! service.isTerminated()) {
}
//join方法是一個阻塞式方法裸卫,表示等待線程結(jié)束
//如果將join方法放到主線程,會導(dǎo)致其他線程被阻塞
//for (Thread thread : list) {
//線程對象的join()
//thread.join();
//}
System.out.println("賬戶余額:¥" + mainAccount.getBalance());
}
}
wait()是讓線程暫停(進入對象等待池)纽竣,然后釋放對象的鎖 --- 在等待池中的線程需要其他線程將其喚醒
設(shè)置優(yōu)先級改變的是線程獲得CPU調(diào)度的幾率
裝潢模式
將線程不安全的容器包裝成線程安全的容器
List<String> list = Collections.synchronizedList(new ArrayList<>());
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<>());
//ArrayList是線程不安全的墓贿,因為它的方法沒有加synchronized保護
//List<String> list = new ArrayList<>();
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++){
service.execute(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100000; j++){
list.add("Hello");
}
}
});
}
service.shutdown();
while (! service.isTerminated()){
}
System.out.println(list.size());
}