線程,定時任務

1. 線程的狀態
  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) {

}
}
}   


   4)多線程安全問題
    當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();//解鎖

}
}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章