java多线程

 一个线程是进程中的执行流程,一个进程可以同时包括多个线程,每个线程可以得到一段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。

进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

2、实现线程的两种方式

2.1、继承Thread类

Thread类是java.lang包中的一个类。

通过该方法实现进程有三个步骤

1)继承Thread类

2)实现run()方法

3)调用start()方法

package com.pjf.thread;

//继承Thread类
public class ThreadTest extends Thread {

    private int count = 10;

    // 重写run()方法
    public void run() {
        while (true) {
            System.out.println(count + " ");
            if (--count == 0) {
                return;
            }
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        // 调用start()方法
        threadTest.start();
    }
}

2.2、实现runnable接口

通过该方法实现进程有四个步骤

1)实现Runnable接口

2)重写run方法

3)通过public Thread(Runnable r)构造方法来创建进程

4)调用start()方法

package com.pjf.runnable;

//实现Runnable接口
public class RunnableTest implements Runnable {

    private int count = 10;

    // 重写run方法
    public void run() {
        while (true) {
            System.out.println(count + " ");
            if (--count == 0)
                return;
        }
    }

    public static void main(String[] args) {
        // 通过public Thread(Runnable r)构造方法来创建进程
        RunnableTest runnableTest = new RunnableTest();
        Thread thread = new Thread(runnableTest);
        // 调用start方法
        thread.start();
    }
}

3、线程的生命周期

线程具有生命周期,包括七个状态,分别为初始状态、就绪状态、运行状态、锁池状态、等待状态、阻塞状态、死亡状态。

初始状态:创建了一个进程对象。

就绪状态:调用了该对象的start()方法。等待获取CPU的使用权就可以运行。

运行状态:获取了CPU,执行程序代码

锁池状态:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

等待状态:调用对象的wait方法,进入等待状态,并释放进程锁。

阻塞状态:调用对象的sleep或join方法,进入休眠状态,休眠结束后,转入就绪状态,等待获取cpu

死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

4、函数说明

sleep();

yeild();

join();

synchronized;

wait();

notify();

notifyAll();

4.1、sleep() 在指定的毫秒数内让当前正在执行的线程休眠

package com.pjf.runnable;

public class RunnableTest implements Runnable {

    private int count = 10;

    public void run() {
        while (true) {
            System.out.println(count + " ");
            count--;
            try {
                // 线程休眠
                Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 0)
                return;
        }
    }
    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        Thread thread = new Thread(runnableTest);
        thread.start();
    }
}

4.2、yeild()让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会

package com.pjf.runnable;

public class RunnableTestYeild implements Runnable {

    private int count = 10;

    public void run() {
        long beginTime = System.currentTimeMillis();
        int count = 0;
        for (int i = 0; i < 50000000; i++) {
            count = count + (i + 1);
            Thread.yield();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用时:" + (endTime - beginTime) + " 毫秒!");
    }

    public static void main(String[] args) {
        RunnableTestYeild runnableTest = new RunnableTestYeild();
        Thread thread = new Thread(runnableTest);
        thread.start();
    }
}

4.3、join()主线程等待子线程的终止后才能继续执行

 泡茶前必须洗茶杯、烧开水,即使泡茶本身的动作的时间短于烧开水的时间,通过join()实现

package com.pjf.join;

public class Water extends Thread {

    public void run() {
    System.out.println("开始烧开水");
    try {        
        Thread.currentThread().sleep(1000);        
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("结束烧开水");
    }    
}
package com.pjf.join;

public class WashTeaCup extends Thread {
    
    public void run() {
        System.out.println("开始洗茶杯");
        for(int i=0;i<5;i++){
            System.out.println("开始洗第"+i+"个茶杯");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("结束洗第"+i+"个茶杯");
        }
    }
}
package com.pjf.join;

public class MakeTea extends Thread {
    private WashTeaCup washTeaCup;
    private Water water;

    public MakeTea(WashTeaCup washTeaCup, Water water) {
        this.washTeaCup = washTeaCup;
        this.water = water;
    }

    public void run() {
        System.out.println("开始泡茶");
        try {
            washTeaCup.join();
            water.join();
            Thread.currentThread().sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("泡茶结束");
    }

    public static void main(String[] args) throws InterruptedException {
        WashTeaCup washTeaCup = new WashTeaCup();
        Water water = new Water();
        MakeTea makeTea = new MakeTea(washTeaCup, water);
        
        makeTea.start();
        water.start();
        washTeaCup.start();
    }
}

4.4、synchronized同步和死锁

参考http://www.cnblogs.com/mengdd/archive/2013/02/16/2913806.html,考虑了四种情况,讲解清晰

public class ThreadTest
{
    public static void main(String[] args)
    {
        Example example = new Example();

        Thread t1 = new Thread1(example);
        Thread t2 = new Thread1(example);

        t1.start();
        t2.start();
    }

}

class Example
{
    public synchronized void execute()
    {
        for (int i = 0; i < 10; ++i)
        {
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println("Hello: " + i);
        }
    }

}

class Thread1 extends Thread
{
    private Example example;

    public Thread1(Example example)
    {
        this.example = example;
    }

    @Override
    public void run()
    {
        example.execute();
    }

}

如果不加synchronized关键字,则两个线程同时执行execute()方法,输出是两组并发的。

如果加上synchronized关键字,则会先输出一组0到9,然后再输出下一组,说明两个线程是顺次执行的。

4.5、wait()、notify()

参考http://www.cnblogs.com/mengdd/archive/2013/02/20/2917956.html

wait()方法使得当前线程必须要等待并释放所有锁,等到另外一个线程调用notify()或者notifyAll()方法。

notify()方法会唤醒一个等待当前对象的锁的线程。如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)

实例:利用两个线程,对一个整形成员变量进行变化,一个对其增加,一个对其减少,利用线程间的通信,实现该整形变量0101这样交替的变更。

NumberTest

public class NumberHolder
{
    private int number;

    public synchronized void increase()
    {
        if (0 != number)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        // 能执行到这里说明已经被唤醒
        // 并且number为0
        number++;
        System.out.println(number);

        // 通知在等待的线程
        notify();
    }

    public synchronized void decrease()
    {
        if (0 == number)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

        }

        // 能执行到这里说明已经被唤醒
        // 并且number不为0
        number--;
        System.out.println(number);
        notify();
    }

}



public class IncreaseThread extends Thread
{
    private NumberHolder numberHolder;

    public IncreaseThread(NumberHolder numberHolder)
    {
        this.numberHolder = numberHolder;
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 20; ++i)
        {
            // 进行一定的延时
            try
            {
                Thread.sleep((long) Math.random() * 1000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            // 进行增加操作
            numberHolder.increase();
        }
    }

}



public class DecreaseThread extends Thread
{
    private NumberHolder numberHolder;

    public DecreaseThread(NumberHolder numberHolder)
    {
        this.numberHolder = numberHolder;
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 20; ++i)
        {
            // 进行一定的延时
            try
            {
                Thread.sleep((long) Math.random() * 1000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            // 进行减少操作
            numberHolder.decrease();
        }
    }

}



public class NumberTest
{
    public static void main(String[] args)
    {
        NumberHolder numberHolder = new NumberHolder();
        
        Thread t1 = new IncreaseThread(numberHolder);
        Thread t2 = new DecreaseThread(numberHolder);
                
        t1.start();
        t2.start();
    }

}

 

posted @ 2017-11-09 09:48  梦天幻  阅读(319)  评论(0编辑  收藏  举报