java基础之 线程

来源:互联网 发布:成都多益网络怎么样 编辑:程序博客网 时间:2024/05/16 04:12

一、Thread类

1 构造函数

        

2 常用方法

static int activeCount() 返回当前线程的线程组中活动线程的数目。

static Thread currentThread() 返回当前正在执行的线程对象的引用。

void setDaemon(boolean on)  将该线程标记为守护线程或用户线程。


二、实现线程的两种方法

1、创建 java.lang.Thread 类的子类,重写该类的 run方 法
2、创建 java.lang.Runnable接 口的实现类,实现接口中的 run 方法

/**********************  创建线程   ***********************************/public class ThreadTest{    public static void main(String[] args) throws InterruptedException{        //创建线程        MyThread myThread = new MyThread("myThread");        myThread.start();        MyRunnable myRunnable = new MyRunnable();        Thread runnableThread = new Thread(myRunnable,"myRunnable");        runnableThread.start();        //获取当前线程的名字        String currName = Thread.currentThread().getName();        for(int i=0; i<200; i++){            System.out.println("线程 " + currName +" 正在运行" + i);        }        System.out.println("线程 " + currName +" 执行结束");    }}class MyThread extends Thread{    public MyThread(String name){        super(name);    }    @Override    public void run(){        for(int i=0; i<200; i++){            System.out.println("线程 " + getName() +" 正在运行" + i);        }        System.out.println("线程 " + getName() +" 执行结束");    }}class MyRunnable implements Runnable{    @Override    public void run() {        String currName = Thread.currentThread().getName();        for(int i=0; i<200; i++){            System.out.println("线程 " + currName +" 正在运行" + i);        }        System.out.println("线程 " + currName +" 执行结束");    }}

三、线程生命周期相关的几个方法


1、yeild(): 若当前线程调用该方法,则由执行状态变为可运行状态

2、wait():当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。

3、join():在一个线程中吊用另外的线程的join()方法,将使当前线程阻塞,等待另一个线程执行完成后再进入可执行状态

4、sleep():当前线程休眠

5、notify() notifyAll():Object对象用于通知处在等待该对象的线程的方法

线程的五大状态:

线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。



    1.新建状态(New): 
        当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

     2.就绪状态(Runnable)

        一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。

        处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。

    3.运行状态(Running)

        当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.

    4. 阻塞状态(Blocked)

        线程运行过程中,可能由于各种原因进入阻塞状态:
        1>线程通过调用sleep方法进入睡眠状态;
        2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
        3>线程试图得到一个锁,而该锁正被其他线程持有;
        4>线程在等待某个触发条件;
        ......           

        所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

    5. 死亡状态(Dead)

        有两个原因会导致线程死亡:
        1) run方法正常退出而自然死亡,
        2) 一个未捕获的异常终止了run方法而使线程猝死。
        为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.



四、方法详解

wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法。

1、sleep()

使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。

Thread.sleep(long millis)必须带有一个时间参数。

sleep(long)使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;

sleep(long)是不会释放锁标志的。

2、yield()

该方法与sleep()类似,只是不能由用户指定暂停多长时间,释放资源之后立即进入就绪状态。

3、join()

join()方法使调用该方法的线程在此之前执行完毕,也就是等待该方法的线程执行完毕后再往下继续执行。注意该方法也需要捕捉异常。

4、wait()

void wait() 在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前,导致当前线程等待。

void wait(long timeout)在其他线程调用此对象的notify() 方法 或者 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。

wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其他shnchronized数据可被别的线程使用。

5、sleep()和yield()

sleep 方法使当前运行中的线程睡眠一段时间,进入不可以运行状态,这段时间的长短是由程序设定的,

yield方法使当前线程让出CPU占有权,但让出的时间是不可设定的。yield()也不会释放锁标志。

6、wait()和notify()、notifyAll()

这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。synchronized关键字用于保护共享数据,阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会访问共享数据呢?此时就用这三个方法来灵活控制。

wait()方法使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。当调用notify()方法后,将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。

notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。


五、notify()和notifyAll()

notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于:

notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。

notify则文明得多他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。

下面是一个很好的例子:

import java.util.*;class Widget...{}class WidgetMaker extends Thread...{    List<Widget> finishedWidgets=new ArrayList<Widget>();    public void run()...{        try...{            while(true)...{                Thread.sleep(5000);//act busy                Widget w=new Widget();                //也就是说需要5秒钟才能新产生一个Widget,这决定了一定要用notify而不是notifyAll                //因为上面两行代码不是同步的,如果用notifyAll则所有线程都企图冲出wait状态                //第一个线程得到了锁,并取走了Widget(这个过程的时间小于5秒,新的Widget还没有生成)                //并且解开了锁,然后第二个线程获得锁(因为用了notifyAll其他线程不再等待notify语句                //,而是等待finishedWidgets上的锁,一旦锁放开了,他们就会竞争运行),运行                //finishedWidgets.remove(0),但是由于finishedWidgets现在还是空的,                //于是产生异常                //***********这就是为什么下面的那一句不能用notifyAll而是要用notify                                                synchronized(finishedWidgets)...{                    finishedWidgets.add(w);                    finishedWidgets.notify(); //这里只能是notify而不能是notifyAll                }            }        }        catch(InterruptedException e)...{}    }        public Widget waitForWidget()...{        synchronized(finishedWidgets)...{            if(finishedWidgets.size()==0)...{                try...{                    finishedWidgets.wait();                }                catch(InterruptedException e)                ...{}            }            return finishedWidgets.remove(0);        }    }}public class WidgetUser extends Thread...{    private WidgetMaker maker;    public WidgetUser(String name,WidgetMaker maker)...{        super(name);        this.maker=maker;    }    public void run()...{        Widget w=maker.waitForWidget();        System.out.println(getName()+"got a widget");    }       public static void main(String[] args) ...{        WidgetMaker maker=new WidgetMaker();        maker.start();        new WidgetUser("Lenny",maker).start();        new WidgetUser("Moe",maker).start();        new WidgetUser("Curly",maker).start();    }}

六、线程安全的问题

1、何时出现线程安全问题:当多个线程访问共享资源的时候

2、使用synchronized解决线程安全问题

1)同步方法 private synchronized boolean getApple(){}

2)同步代码块 synchronized(obj){}

/**********************  线程安全   ***********************************/public class ShareApple implements Runnable{    private int appleCount = 5;    private boolean isRun = true;    @Override    public void run() {        while(isRun){            isRun = getApple();        }        if(appleCount <= 0){            System.out.println(Thread.currentThread().getName()                     + " 苹果拿完了");            //结束线程            return;        }    }    private boolean getApple(){        boolean flag = false;        synchronized(this){            if(appleCount > 0){                flag = true;                appleCount --;                System.out.println(Thread.currentThread().getName()                         + " 拿走了一个苹果,还剩"+ appleCount + "个苹果");            }        }        return flag;    }        public static void main(String[] args){        ShareApple shareApple = new ShareApple();        Thread th_xiaoming = new Thread(shareApple);        Thread th_xiaoqiang= new Thread(shareApple);        th_xiaoming.setName("小明");        th_xiaoqiang.setName("小强");        th_xiaoming.start();        th_xiaoqiang.start();    }}

七、ThreadLocal实现线程内的数据共享

package com.step.thread;import java.util.Random;public class ThreadLocalTest {public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();public static void main(String[] args) {for(int i = 0; i < 2; i++){new Thread(new Runnable() {@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " put data: " + data);threadLocal.set(data);new A().get();new B().get();}}).start();}}static class A{public void get(){System.out.println("A from " + Thread.currentThread().getName() + " get data: " + threadLocal.get());}}static class B{public void get(){System.out.println("B from " + Thread.currentThread().getName() + " get data: " + threadLocal.get());}}}class MyThreadLocalData{private static ThreadLocal<MyThreadLocalData> threadLocal = new ThreadLocal<MyThreadLocalData>();private MyThreadLocalData(){}public MyThreadLocalData getInstance(){MyThreadLocalData instance = threadLocal.get();if(instance == null){instance = new MyThreadLocalData();}return instance;}}

八、线程之间资源共享 Runnable


package com.step.thread;public class RunnableTest {public static void main(String[] args) {ShareDataOperator shareDataOperator = new ShareDataOperator();for(int i = 0; i < 4; i++){Thread t1 = new Thread(new MyRunnable(shareDataOperator));t1.start();}}}class MyRunnable implements Runnable{ShareDataOperator shareDataOperator = null;//构造函数中接收参数实现资源共享public MyRunnable(ShareDataOperator shareDataOperator){this.shareDataOperator = shareDataOperator;}@Overridepublic void run() {shareDataOperator.add();}}class ShareDataOperator{int shareData = 0;public synchronized void add(){for(int i = 0; i < 20; i++){shareData++;System.out.println(Thread.currentThread().getName() + " " + shareData);}}}

编程题一:

子线程循环10次,主线程循环100次,再子线程循环10次,主线程循环100次,如此往复50次
package com.step.thread;import org.junit.Test;public class ThreadTest {@Testpublic void tt() throws InterruptedException{final Output output = new Output();int i = 0;while(i < 50){i++;new Thread(new Runnable() {@Overridepublic void run() {output.subThread();}}).start();output.mainThread();}}}class Output{//判断执行哪个方法private boolean runSub = true;//子线程输出public synchronized void subThread(){if(!runSub){try {this.wait();} catch (InterruptedException e) {}}for(int i = 0; i < 10; i++){System.out.println("thread sub ....... " + i);}runSub = false;this.notify();}//主线程输出public synchronized void mainThread(){if(runSub){try {this.wait();} catch (InterruptedException e) {}}for(int i = 0; i < 100; i++){System.out.println("thread main ....... " + i);}runSub = true;this.notify();}}

编程题二

写四个线程,两个线程每次加一,两个线程每次减一
package com.step.thread;public class ThreadLocalT {static Operator oper = new Operator();public static void main(String[] args) {Thread t1 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.add();}}});Thread t2 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.add();}}});Thread t3 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.minus();}}});Thread t4 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.minus();}}});t1.start();t2.start();t3.start();t4.start();}}class Operator{public int j = 0;public synchronized void add(){j++;System.out.println(Thread.currentThread().getName() + " add " + j);}public synchronized void minus(){j--;System.out.println(Thread.currentThread().getName() + " minus " + j);}}

九、Lock

用lock改写编程题二
package com.step.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class LockTest {static Operator oper = new Operator();public static void main(String[] args) {Thread t1 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.add();}}});Thread t2 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.add();}}});Thread t3 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.minus();}}});Thread t4 = new Thread(new Runnable(){@Overridepublic void run() {while(true){oper.minus();}}});t1.start();t2.start();t3.start();t4.start();}static class Operator{Lock lock = new ReentrantLock();public int j = 0;public void add(){lock.lock();j++;System.out.println(Thread.currentThread().getName() + " add " + j);lock.unlock();}public void minus(){lock.lock();j--;System.out.println(Thread.currentThread().getName() + " minus " + j);lock.unlock();}}}

读写锁 ReadWriteLock

package com.step.thread;import java.util.Random;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 读写锁 * */public class ReadWriteLockTest {public static void main(String[] args) {final MyQueue myQueue = new MyQueue();//启动10个线程进行写操作for (int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {myQueue.put();}}).start();}//启动10个线程进行读操作for (int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {myQueue.get();}}).start();}}}class MyQueue{private Object data = null;ReadWriteLock rwLock = new ReentrantReadWriteLock(); //写操作public void put(){rwLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + " start write ..........");Thread.sleep(1000);data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " end write   .........." + data);} catch (Exception e) {e.printStackTrace();}finally{rwLock.writeLock().unlock();}}//读操作public void get(){rwLock.readLock().lock();try {System.out.println(Thread.currentThread().getName() + " start read ..........");Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " end read   .........." + data);} catch (Exception e) {e.printStackTrace();}finally{rwLock.readLock().unlock();}}}

模拟缓存系统
package com.step.thread;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 模拟缓存系统 * @author mlu * */public class CacheDemo {//用于存储数据private Map<String, Object> cache = new HashMap<String, Object>();//读写锁private ReadWriteLock rwLock = new ReentrantReadWriteLock();//从缓存中读取数据public Object getData(String key){rwLock.readLock().lock();Object value = null;try {value = cache.get(key);if(value == null){//为空时,从数据库读取,此时释放读锁,增加写锁rwLock.readLock().unlock();rwLock.writeLock().lock();try {//读取完数据并释放写锁后,其他线程不需要进入读数据库的操作if(value == null){//从数据库读取数据value = "aa";cache.put(key, value);}} finally{rwLock.writeLock().unlock();rwLock.readLock().lock();}}} finally{rwLock.readLock().unlock();}return value;}}

十、condition

用condition改写编程题一
package com.step.thread;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import org.junit.Test;/** * 用condition改写 * 子线程循环10次,主线程循环100次,再子线程循环10次,主线程循环100次,如此往复50次 * */public class ConditionTest {@Testpublic void tt() throws InterruptedException{final Output output = new Output();int i = 0;while(i < 50){i++;new Thread(new Runnable() {@Overridepublic void run() {output.subThread();}}).start();output.mainThread();}}static class Output{//判断执行哪个方法private boolean runSub = true;Lock lock = new ReentrantLock();Condition condition = lock.newCondition();//子线程输出public void subThread(){lock.lock();try {//使用while是为了唤醒之后再判断一次条件,确保是正常唤醒while(!runSub){try {System.out.println("sub wait ..............");condition.await();} catch (InterruptedException e) {}}for(int i = 0; i < 10; i++){System.out.println("thread sub ....... " + i);}runSub = false;condition.signal();} finally {lock.unlock();}}//主线程输出public void mainThread(){lock.lock();try {//使用while是为了唤醒之后再判断一次条件,确保是正常唤醒while(runSub){try {System.out.println("main wait ..............");condition.await();} catch (InterruptedException e) {}}for(int i = 0; i < 100; i++){System.out.println("thread main ....... " + i);}runSub = true;condition.signal();} finally{lock.unlock();}}}}

改为三个线程,线程1执行后线程2执行,线程2执行后线程3执行
package com.step.thread;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import org.junit.Test;/** * 用condition改写 * 线程一循环10次,线程二循环50次,线程三循环100次,如此往复50次 * */public class ConditionTest2 {@Testpublic void tt() throws InterruptedException{final Output output = new Output();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {output.firThread();}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {output.secThread();}});Thread t3 = new Thread(new Runnable() {@Overridepublic void run() {output.thrThread();}});int i = 0;while(i < 50){System.out.println(">>>>>>>>>>>>> " + i);i++;//t1.start();//t2.start();//t3.start();new Thread(new Runnable() {@Overridepublic void run() {output.firThread();}}).start();new Thread(new Runnable() {@Overridepublic void run() {output.secThread();}}).start();new Thread(new Runnable() {@Overridepublic void run() {output.thrThread();}}).start();}}static class Output{//判断执行哪个方法private int runThread = 1;Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();Condition condition2 = lock.newCondition();Condition condition3 = lock.newCondition();//线程一public void firThread(){lock.lock();try {//使用while是为了唤醒之后再判断一次条件,确保是正常唤醒while(runThread != 1){try {condition1.await();} catch (InterruptedException e) {}}for(int i = 0; i < 10; i++){System.out.println("thread 1 ....... " + i);}//唤醒线程2runThread = 2;condition2.signal();} finally {lock.unlock();}}//线程2public void secThread(){lock.lock();try {//使用while是为了唤醒之后再判断一次条件,确保是正常唤醒while(runThread != 2){try {condition2.await();} catch (InterruptedException e) {}}for(int i = 0; i < 50; i++){System.out.println("thread 2 ....... " + i);}//唤醒线程3runThread = 3;condition3.signal();} finally{lock.unlock();}}//线程3public void thrThread(){lock.lock();try {//使用while是为了唤醒之后再判断一次条件,确保是正常唤醒while(runThread != 3){try {condition3.await();} catch (InterruptedException e) {}}for(int i = 0; i < 100; i++){System.out.println("thread 3 ....... " + i);}//唤醒线程1runThread = 1;condition1.signal();} finally{lock.unlock();}}}}

模拟阻塞队列

package com.step.thread;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * 模拟阻塞队列 * */public class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr = 0; //存指针int takeptr = 0;//取指针int count = 0;//存函数public void put(Object x){lock.lock();try {//此时不可存while(count == items.length){notFull.await();}//存入数组items[putptr] = x;++count;//存到末尾后,再从最前面开始存if(++putptr == items.length) putptr=0;//存入后可取notEmpty.signal();} catch (Exception e) {}finally{lock.unlock();}}//取函数public Object take(){lock.lock();Object item = null;try {//此时不可取while(count == 0){notEmpty.await();}//取数据item = items[takeptr];count--;//取到末尾后,再从最前面开始取if(takeptr == items.length) takeptr=0;//取出后可存notFull.signal();} catch (Exception e) {}finally{lock.unlock();}return item;}}



0 0
原创粉丝点击