多线程

来源:互联网 发布:阿里云 域名 指向淘宝 编辑:程序博客网 时间:2024/06/05 23:54

一、
1、什么是多线程程序?
有多条执行路径的程序称为多线程程序。
2、进程与线程之间的关系?
线程是依赖进程存在的,而一个线程相当于进程中的某个任务。
二、如何去实现一个多线程?
实现多线程的有关方法:
1、开始执行线程的方法:

public void start()//使用此方法要注意:线程只能启动一次,如果启动第二次会出现“线程状态异常”---IllegalThreadStateException

2、获取以及设置线程的名称:

public final String getName()//返回线程的名称public final void setName(String name)//改变线程名称,使之与参数name相同//设置线程名称的三种方法:  1)通过有参构造  2)无参+setName(String name)  3)public Thread(String name)//分配新的Thread对象

3、线程的优先级问题(注意:优先级高的线程抢占到CPU执行权的概率大,但不一定就能抢到)

public final int getPriority()//返回线程的优先级//线程的优先级有:1)public static final int MAX_PRIORITY//优先级为10,最高优先级2)public static final int MIN_PRIORITY//优先级为1,最低优先级3)public static final int NORM_PRIORITY//优先级为5,默认优先级

4、线程的等待,睡眠以及其他方法:

public final void join()//等待该线程终止    throws InterruptedExceptionpublic static void yeild()//暂停当前正在执行的线程,并执行其他线程但是并不保证另一个线程就一定能抢到执行权public static void sleep(long millis)//线程睡眠,参数为时间毫秒值    throws InterruptedExceptionpublic final void stop()//强迫线程停止public void interrupt()//中断线程的一种状态public static Thread currentThread()//返回当前正在执行的对象

有三个方法实现多线程程序:
方法一(继承自Thread类):
步骤:1.自定义一个类使其继承自Thread类;
2·在自定义的类中重写Thread类中的run()方法;(run()中心写的是一些耗时的代码:例如循环语句,线程睡眠,线程等待)
3·在主线程中创建自定义类的实例;
4·启动线程;
具体程序实现如下:

//子线程:package _14.homework;public class SetDemo extends Thread {    @Override    public void run() {        for (int x = 0; x < 200; x++)            System.out.println(x);    }}//主线程:package _14.homework;public class Demo3 {    public static void main(String[] args){        SetDemo st1=new SetDemo();        SetDemo st2=new SetDemo();        st1.start();        st2.start();    }}

方法二(实现Runnable接口):
步骤:1·自定义一个类并使其实现Runnable接口;
2·在自定义类中重写该接口的run()方法;
3·在主线程中创建自定义类的实例对象;
4·创建Thread类对象将自定类的实例对象作为参数进行传递;
5·分别启动线程;
具体代码实现如下:

//子线程:package _14.homework;public class ThreadDemo implements Runnable {    @Override    public void run() {        for (int x = 0; x < 200; x++) {            System.out.println(x);        }    }}//主线程:package _14.homework;public class Demo4 {    public static void main(String[] args) {        ThreadDemo td1 = new ThreadDemo();        ThreadDemo td2 = new ThreadDemo();        Thread t1 = new Thread(td1);        Thread t2 = new Thread(td2);        t1.start();        t2.start();    }}

方法三(实现Callable接口)
步骤:1·自建一个类实现Callable接口;
2·利用工厂类创建线程池对象;
3·提交Callable任务;
4·结束线程池;
具体代码实现如下:

//子线程:package _14.homework;import java.util.concurrent.Callable;public class CallableDemo implements Callable<Object> {    @Override    public Object call() throws Exception {        for (int x = 0; x < 200; x++) {            System.out.println(Thread.currentThread().getName() + ":" + x);        }        return null;    }}//主线程:package _14.homework;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test {    public static void main(String[] args) {        ExecutorService threadPool = Executors.newFixedThreadPool(3);        threadPool.submit(new CallableDemo());        threadPool.submit(new CallableDemo());        threadPool.submit(new CallableDemo());        threadPool.shutdown();    }}

三、如何设置一个守护线程?(注意:当正在运行的线程都是守护线程时,Java虚拟机退出并且设置守护线程的方法必须在线程启动前调用!)

public final void setDaemon(boolean on)//若将on设置为true,则将一个线程设置为了守护线程;

具体代码实现如下:

//子线程:package _14.homework;public class ThreadDemo2 extends Thread {    @Override    public void run() {        for(int x=0;x<100;x++){            System.out.println(getName()+": "+x);        }    }}//主线程:package _14.homework;public class Test2 {    public static void main(String[] args){        ThreadDemo2 td1=new ThreadDemo2();        ThreadDemo2 td2=new ThreadDemo2();        td1.setName("老二");        td2.setName("老三");        td1.setDaemon(true);        td2.setDaemon(true);        td1.start();        td2.start();        Thread.currentThread().setName("老大");        for(int i=0;i<10;i++){            System.out.println(Thread.currentThread().getName()+": "+i);        }    }}

由于上面的方式存在安全性问题,我们怎么检验该多线程是否安全?
三个标准:1.是否是多线程环境;
2.是否有共享数据;
3.是否有多条语句对共享数据进行操作;
四、同步机制:
既然存在安全问题我们如何去解决这些安全问题呢?
解决的方式就是同步机制!
首先同步锁:

同步代码块:synchronized(同步锁对象){           //对共享数据进行操作的多条代码         }         //同步锁对象可以是Object类以及任意的Java类

具体代码实现如下:

//子线程:package _14.homework;public class SellTicketDemo implements Runnable {    public static int tickets = 100;    private Object obj = new Object();    @Override    public void run() {        while (true) {            synchronized (obj) {                if (tickets > 0) {                    try {                        Thread.sleep(200);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName()                            + "出售:  第  " + (tickets--) + " 张票");                }            }        }    }}//主线程:package _14.homework;public class SellTicket {    public static void main(String[] args){        SellTicketDemo std=new SellTicketDemo();        Thread t1=new Thread(std,"窗口1");        Thread t2=new Thread(std,"窗口2");        Thread t3=new Thread(std,"窗口3");        t1.start();        t2.start();        t3.start();         }}

同步方法(如果一个方法进来之后就是同步代码块,那么就可以将其改进为同步方法):
非静态的同步方法的锁对象为Object类以及任意的Java类型对象!
而静态的同步方法的锁对象则是当前类名的class属性:即类名.class

//子线程:package _14.homework;public class SellTicketDemo implements Runnable {    public static int tickets = 100;    private int x;    @Override    public void run() {        while (true) {            if (x % 2 == 0) {                synchronized (SellTicketDemo.class) {                    if (tickets > 0) {                        try {                            Thread.sleep(100);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        System.out.println(Thread.currentThread().getName()                                + "正在出售: 第  " + (tickets--) + " 张票");                    }                }            }else{                sellTicketDemo();            }            x++;        }    }    public static synchronized void sellTicketDemo(){        if (tickets > 0) {            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()                    + "正在出售: 第  " + (tickets--) + " 张票");        }    }}//主线程:package _14.homework;public class SellTicket {    public static void main(String[] args){        SellTicketDemo std=new SellTicketDemo();        Thread t1=new Thread(std,"窗口1");        Thread t2=new Thread(std,"窗口2");        Thread t3=new Thread(std,"窗口3");        t1.start();        t2.start();        t3.start();         }}

五、等待唤醒机制:
利用同步机制我们解决了上面的线程安全问题,但执行的结果有可能出现死锁以及结果是一段一段的相同的结果,那么怎样可以让执行结果变为一个线程执行完一次,另一个线程开始执行呢?采用等待唤醒机制!
具体代码实现如下:

//学生类:package _14.homework;public class Student2 {             String name;        int age ;        String sex;        boolean flag ;}//生产者线程:package _14.homework;public class SetDemo1 implements Runnable {    private int x = 0;    private Student2 s;    public SetDemo1(Student2 s) {        this.s = s;    }    @Override    public void run() {        while (true) {            synchronized (s) {                if (s.flag) {                    try {                        s.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                if (x % 2 == 0) {                    s.name = "张三";                    s.age = 30;                    s.sex = "男";                } else {                    s.name = "翠花";                    s.age = 26;                    s.sex = "女";                }                x++;                s.flag = true;                s.notify();            }        }    }}//消费者线程:package _14.homework;public class GetThread2 implements Runnable {    private Student2 s;    public GetThread2(Student2 s) {        this.s = s;    }    @Override    public void run() {        while(true){            synchronized (s) {                if(!s.flag){                    try {                        s.wait() ;                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                System.out.println(s.name + "------" + s.age+"------"+s.sex);                s.flag = false ;                s.notify() ;            }        }    }}//主线程:package _14.homework;public class StudentDemo2 {    public static void main(String[] args) {        Student2 s = new Student2() ;        SetDemo1 sd = new SetDemo1(s) ;        GetThread2 gt = new GetThread2(s) ;        Thread t1 = new Thread(sd) ;        Thread t2 = new Thread(gt) ;                t1.start() ;        t2.start() ;    }   }

六、线程组:
有关线程组的一些方法:

public class ThreadGroup{}//多个线程的集合public final String getName() //返回线程组名称public final TreadGroup getThreadGroup()//返回该线程所在线程组public ThreadGroup(String name)//构造一个新的线程组public Thread(ThreadGroup group,Runnable target,String name)public final void setDaemon(boolean daemon)//更改线程组的后台程序状态//如果将参数设置为true则是将线程组中的所有子线程都设置为了守护线程

七、线程池(当程序中要大量创建生存期很短的线程时,最好考虑线程池):当启动线程完毕后,不会被垃圾回收器回收而是又回到线程池中变成空闲状态!
创建线程池的方法:

public static ExecutorService newCachedPool()//创建一个根据需要创建新线程的线程池public static ExecutorService newFixedThreadPool(int nThread)//创建一个可重用固定线程数的线程池public static ExecutorService newSingleThreadExecutor()

关闭线程池的方法:

void shutdowm();//关闭线程池<T>Future<T>submit(Callable <T> task)//提交一个任务用于执行Future<?>submit(Runnable task)//提交一个Runnable任务用于执行

具体实现即为多线程实现的第三种方式;
八、定时器Timer类
定时器的具体方法:

public void schedule(TimerTask task,ling delay)//安排在指定的时间执行public void schedule(TimerTask task,long delay,long period)//安排在指定延迟后执行指定任务public void cancel()//指定在多少毫秒后每period毫秒重复执行

TimerTask需要被执行的任务类是一个抽象类不能直接实例化
具体代码实现如下:

//package _14.homework;import java.util.Timer;public class TimerDemo {    public static void main(String[] args){    Timer t = new Timer() ;    t.schedule(new MyTask(),3000,1000 );    }}
package _14.homework;import java.util.TimerTask;class MyTask extends TimerTask{    @Override    public void run() {        System.out.println("世界如此美好,");        System.out.println("你却如此暴躁,");        System.out.println("这样不好!");        System.out.println("不好!!!");        System.out.println();    }}
原创粉丝点击