1) NEW: 線程剛創建。
2) RUNNABLE: 可執行的或正在執行的線程所處的狀態。
3) TERMINATED: 已退出的線程。
4) BLOCKED: 受阻塞並等待某個監視器鎖的線程所處的狀態。
5) WAITING: 等待狀態。
6) TIMED WAITING: 超時等待狀態。
例1:
package com.wx;
/**
* @author wx
* 線程的睡眠
*/
public class Test1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t=new Thread(new MyThread1());
t.start();
}
}
class MyThread1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
例2:
package com.wx;
/**
* @author wx
* 線程的讓步
*/
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("主線程");
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"-->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Thread t1=new Thread(new MyThread2());
t1.setName("線程一:");
t1.start();
Thread t2=new Thread(new MyThread2());
t2.setName("線程二:");
t2.start();
}
}
class MyThread2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
if(i==5){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"->"+i);
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//class MyThread3 implements Runnable{
//
// @Override
// public void run() {
// // TODO Auto-generated method stub
// for(int i=0;i<10;i++){
// if(i==5){
// Thread.yield();
// }
// System.out.println(Thread.currentThread().getName()+"->"+i);
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// }
//}
例3:
package com.wx;
/**
* @author wx
* 線程的加入
*/
public class Test3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t1=new Thread(new MyThread3());
t1.setName("線程一:");
t1.start();
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"->"+i);
if(i==5){
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class MyThread3 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"->"+i);
}
}
}
☆2. 線程狀態的轉換:
1) RUNNABLE --> BLOCKED: 當前線程要操作的資源被其它線程鎖定。
BLOCKED --> RUNNABLE: 當要操作的資源上的同步鎖被釋放了。
2) RUNNABLE --> WAITING:
當前線程中調用了某個Object的wait()方法,讓本線程進入WAITING狀態。
當前線程中調用了另一個線程的join()方法,當前線程進入WAITING狀態。
WAITING --> RUNNABLE:
在某個線程中調用對應Object的notify(),notifyAll()方法時,等待在這個Object對象上的線程就會進入RUNNABLE。
那個join進來的線程執行完畢時,當前線程會進入RUNNABLE。
3) RUNNABLE --> TIMED WAITING:
當前線程中調用了某個Object的wait(long time)方法,讓本線程進入TIMED WAITING狀態。
當前線程中調用了sleep(long timeout)方法,當前線程進入TIMED WAITING狀態。
當前線程中調用了其它線程的join(long millis)方法,當前線程進入TIMED WAITING狀態。
TIMED WAITING --> RUNNABLE:
等待時間已到,調用notify(), notifyAll()。
睡眠時間結束。
等待時間已到。
3. 線程的優先級:1~10級。默認是NORM_PRIORITY(5), 最高級別MAX_PRIORITY(10), 最低MIN_PRIORITY(1)
Thread類提供了setPrority(int level)方法來更改優先級。並不是所有的操作系統都支持線程的優先級。
例1:
package com.wx;
/**
* @author wx
* 線程優先級
*/
public class Test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getPriority());
Thread.currentThread().setPriority(10);
Thread t=new Thread(new MyThread4());
t.setName("線程一:");
t.setPriority(10);
System.out.println(t.getPriority());
t.start();
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
System.out.println("主線程執行完畢");
}
}
class MyThread4 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
例2:
package com.wx;
/**
* @author wx
* 生產者和消費者
*
* 解決問題:
* 生產者過快消費者會漏掉一部分數據
* 消費者過快則每次取到的產品都是一樣的
*
* 理想的情況: 生產者和消費者保持一致的狀態
*/
public class Test5 {
public static void main(String[] args) {
Clerk clerk=new Clerk();
ProductThread pt=new ProductThread(clerk);
SaleThread st=new SaleThread(clerk);
pt.start();
st.start();
}
}
/**
* 店員
* @author wx
*
*/
class Clerk{
private int count;//表示商店存放產品的數量 20
public synchronized void addProduct(){
//如果店鋪存放的產品大於20,則通知生產者等一下
if(count>20){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("生產者生產第"+(count+1)+"個產品");
count++;
//喚醒生產者和消費者
notifyAll();
}
}
/**
* 消費,賣產品
*/
public synchronized void salProduct(){
if(count<0){
try {
wait();//讓消費者等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("消費者取走第"+(count+1)+"個產品");
count--;
notifyAll();//生產者+消費者
}
}
}
/**
* 生產者線程
* @author wx
*
*/
class ProductThread extends Thread{
private Clerk clerk;
public ProductThread(Clerk clerk){
this.clerk=clerk;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep((long)(Math.random()*100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//調用店鋪的addProduct方法,添加產品到商鋪
clerk.addProduct();
}
}
}
class SaleThread extends Thread{
private Clerk clerk;
public SaleThread(Clerk clerk){
this.clerk=clerk;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep((long)(Math.random()*100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.salProduct();
}
}
}
★4. 線程的同步:
1) 如果在run()方法中操作到了成員變量(共享數據),那麼就可能會出現線程不同步問題(線程安全問題).
2) 使用synchronized關鍵字來解決。 鎖的粒度儘量小。。。
a) 同步塊: synchronized(this.getClass()){ 操作到成員變量的代碼; }
b) 同步方法:public synchronized void test() { ... } //應該只鎖操作到成員變量的方法
c) JDK5.0提供了Lock,可以很方便添加到代碼中。
static Lock locker = new ReentrantLock();
locker.lock();
...
locker.unlock();
3) 死鎖問題:仔細分析,把鎖的粒度加大一些。
例:
package com.wx;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author wx
*
*/
public class Test6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
List list=new ArrayList();
synchronized (list) {
}
List list2=Collections.synchronizedList(new ArrayList());
synchronized (list2) {
}
}
}
當run()方法體內的代碼操作到了成員變量(共享數據)時,就可能會出現多線程安全問題(線程不同步問題)。
編程技巧
在方法中儘量少操作成員變量,多使用局部變量
5. 線程間的交互:Object提供的wait(), notify(), notifyAll()。 生產者消費者問題。
6.容器類線程安全問題
容器類大多數默認都沒有考慮線程安全問題,程序必須自行實現同步以確保共享數據在多線程下存取不會出錯:
可以用synchronized來鎖住這個對象
synchronized(list){ list.add(…); }
可以使用java.uitl.Collections的synchronizedXXX()方法來返回一個同步化的容器對象
List list = Collections.synchronizedList(new ArrayList());
這種方式在迭代時仍要用synchronized修飾
JDK5.0之後,新增了java.util.concurrent這個包,其中包括了一些確保線程安全的容器類,
如ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet,
它們在效率與安全性上取得了較好的平衡。
6. 定時任務:
1) java.util.Timer 計時器類
2) java.util.TimerTask 任務類
例1:
package com.wx;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author wx
* Timer定時器
*/
public class Test7 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Timer t=new Timer();
//t.schedule(new MyTimerTask(), 1000L, 2000L);
//t.schedule(new MyTimerTask(), new Date());
//t.schedule(new MyTimerTask(), new Date(), 1000L);
//t.scheduleAtFixedRate(new MyTimerTask(), 1000L, 2000L);
//t.scheduleAtFixedRate(new MyTimerTask(), new Date(), 2000L);
String str="2014-09-12 16:00:00";
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date=format.parse(str);
//t.scheduleAtFixedRate(new MyTimerTask(), date, 2000L);
t.schedule(new MyTimerTask(), date, 2000L);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean flag=true;
while(flag){
try {
int ch=System.in.read();
if(ch=='e'){
t.cancel();
flag=false;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("任務完成!!!")
}
}
class MyTimerTask extends TimerTask{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("豬起牀了...");
}
}
例2:
package com.wx;
/**
* @author wx
*用程序模擬鐵路售票系統:實現通過四個售票點發售某日某次列車的1000張車票,一個售票點用一個線程表示。
*/
public class Test10 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyTickets my=new MyTickets();
//創建四個窗口
Thread t1=new Thread(my);
t1.setName("窗口一:");
t1.start();
Thread t2=new Thread(my);
t2.setName("窗口二:");
t2.start();
Thread t3=new Thread(my);
t3.setName("窗口三:");
t3.start();
Thread t4=new Thread(my);
t4.setName("窗口四:");
t4.start();
}
}
class MyTickets implements Runnable{
int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
if(count<100){
System.out.println(Thread.currentThread().getName()+"正在賣出第"+(count+1)+"票");
count++;
}else{
break;
}
}
}
}
例3:
package com.wx;
/**
* @author wx
*用程序模擬鐵路售票系統:實現通過四個售票點發售某日某次列車的1000張車票,一個售票點用一個線程表示。
同步代碼塊
*/
public class Test11 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyTickets2 my=new MyTickets2();
//創建四個窗口
Thread t1=new Thread(my);
t1.setName("窗口一:");
t1.start();
Thread t2=new Thread(my);
t2.setName("窗口二:");
t2.start();
Thread t3=new Thread(my);
t3.setName("窗口三:");
t3.start();
Thread t4=new Thread(my);
t4.setName("窗口四:");
t4.start();
}
}
class MyTickets2 implements Runnable{
int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (this) {
if(count<100){
System.out.println(Thread.currentThread().getName()+"正在賣出第"+(count+1)+"票");
count++;
}else{
break;
}
}
}
}
}
例4:
package com.wx;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author lw
*用程序模擬鐵路售票系統:實現通過四個售票點發售某日某次列車的1000張車票,一個售票點用一個線程表示。
顯示加鎖
*/
public class Test12 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyTickets3 my=new MyTickets3();
//創建四個窗口
Thread t1=new Thread(my);
t1.setName("窗口一:");
t1.start();
Thread t2=new Thread(my);
t2.setName("窗口二:");
t2.start();
Thread t3=new Thread(my);
t3.setName("窗口三:");
t3.start();
Thread t4=new Thread(my);
t4.setName("窗口四:");
t4.start();
}
}
class MyTickets3 implements Runnable{
private Lock lock=new ReentrantLock();//獲取鎖的對象
int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
lock.lock();//加鎖
if(count<100){
System.out.println(Thread.currentThread().getName()+"正在賣出第"+(count+1)+"票");
count++;
}else{
break;
}
lock.unlock();//解鎖
}
}
}