一、繼承Thread類
- 多線程併發操作同一數據時, 就有可能出現線程安全問題
- 使用同步技術可以解決這種問題, 把操作數據的代碼進行同步, 不要多個線程一起操作
需求:鐵路售票,一共100張票,通過四個窗口賣完.
package com.soar.syn;
public class Demo3_Ticket {
/*
* 需求:鐵路售票,一共100張,通過四個窗口賣完.
*/
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread{
private static int ticket = 100;
//private static Object obj = new Object(); //如果用應用數據類型的成員變量當作鎖對象,必須是靜態的
public void run(){
while(true){
synchronized(Ticket.class){
if(ticket == 0){
break;
}
try {
Thread.sleep(10); //線程1睡,線程2睡,線程3睡,線程4睡
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"這是第"+ ticket-- + "號票");
}
}
}
}
二、使用Runnable接口
package com.soar.syn;
public class Demo4_Ticket {
/*
* 火車站賣票的例子用實現Runnable接口
*/
public static void main(String[] args) {
MyTicket mt = new MyTicket();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
//多次啓動一個線程是非法的
/*Thread t1 = new Thread(mt);
t1.start();
t1.start();
t1.start();
t1.start();*/
}
}
class MyTicket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
synchronized(Ticket.class){ //鎖對象也可以用this
if(ticket == 0){
break;
}
try {
Thread.sleep(10); //線程1睡,線程2睡,線程3睡,線程4睡
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"這是第"+ ticket-- + "號票");
}
}
}
}
三、一些相關的線程安全類
- Vector是線程安全的
- ArrayList是線程不安全的
- StringBuffer是線程安全的
- StringBuilder是線程不安全的
- Hashtable是線程安全的
- HashMap是線程不安全的
Collections.synchroinzed(xxx)可以將線程不安全的類轉換爲線程安全的類