关闭

JAVA线程

标签: Thread多线程
208人阅读 评论(0) 收藏 举报
分类:
  • 1.线程的创建(附带代码块)
       1.1实现线程的两个办法
        (1)继承Thread类创建多线程(extends)(代码块1)
        (2)实现Runnable接口创建多线程(implements)(代码块2)
        (代码块1)
class dfds {
        public static void main(String[] args)    
{
    MyThread myThread=new MyThread(); //创建MyThread实例对象
    myThread.start();//调用MyThread方法
        while(true)
            System.out.println("main()方法在运行");
    }
}
class MyThread extends Thread{
    public void run(){
        while (true) {
            System.out.println("MyThread类的run()方法在运行");

        }
    }
}
    (代码块2)
class dfds {
        public static void main(String[] args)
    {
     MyThread myThread=new MyThread();  //创建MyThread的实例对象
       Thread thread =new Thread(myThread);  //创建线程对象
        thread.start();  //开启线程执行线程中的run()方法
        while(true)
            System.out.println("main()方法在运行");

    }
}
class MyThread implements Runnable{
    public void run(){    
//线程的代码段,当调用start()方法时,线程从此处开始执行
        while (true) {
            System.out.println("MyThread类的run()方法在运行");

        }
    }
}
  • 2.两种实现多线程方式的对比分析
             Thread.currentThread().getName()
        (1)继承Thread类创建多线程(extends) 没有共享同一个资源
        (2)实现Runnable接口创建多线程(implements)享一个资源
        用Thread类创建的多线程没有将100张机票分成四个窗口来出售,而是一个窗口出售一百张
        用Runnable接口的则将100张机票分成四个窗口来出售,一个窗口出售25张


  •     实现Runnable接口相对于继承Thread类来说,有下列显著的好处:
  • 适合多个相同程序的线程去处理同一个资源的情况,吧线程通程序代码,数据有效分离,很好地体现面向对象的设计思想
  • 可以避免由于java的单继承带来的局限性,在开发中经常碰见一种情况,就是使用了一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,阿么就只能采用Runnable接口的方式。
  • 实际上,大部分 的应用程序都是采用第二种方式来创建多线程,寄实现Runnable接口。



  •   3. 后台线程
        后台线程是相对前台线程来说的,在开启线程前先调用.setDaemon(true)则将前台线程转化为后台线程。
    后台线程最主要的是:进程中只有后台线程运行时,进程就会结束。
                注意:要将某个线程设置为后台线程,必须在改线程启动之前,也就是说setDaemon()方法必须子啊start()方法前调用,否则就会引发IllegalThreadStateException异常。



  •   4 线程生命周期及状态转换
  • 1.新建状态
  • 创建一个线程对象后,改线程对象就处于新建状态,此时它不能运行,和其他JAVA对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征。
  • 2.就绪状态
  • 当对象调用了start()方法后,该线程就进入了就绪状态。处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,是否获得CPU的使用权开始运行,还需要等待系统的调度
  • 3.运行状态
  • 如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态,当一个线程启动后,它不可能一直处于运行状态(除非他的线程执行体足够短,瞬间就结束了),当使用完系统分配的时间后,系统就会剥夺改线程足够的CPU资源,让其他线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才可能装换为运行状态;
  • 4.阻塞状态
  • 一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。
  • 下面列举一下线程由运行状态转换为阻塞状态的原因,以及如何从阻塞状态转化为就绪状态
  • 当线程试图获取某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程就会进入阻塞状态,如果想从这个阻塞状态进图就绪状态必须获取到其他线程所持有的锁。
  • 当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO方法返回。
  • 当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程
  • 当线程调用了Thread的sleep(long millis)方法时,也会使线程进入阻塞状态,在这种情况下,只需要等到线程睡眠时间到了以后,线程就会进入就绪状态。
  • 当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态;
  • 需要注意的是:线程只会从阻塞状态进入就绪状态,而不能直接进入运行状态,也就说结束阻塞后的线程需要进入 可运行池等待系统的调度;
  • 5死亡状态
  • 线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常、错误,线程就会进入死亡状态,线程将不再拥有运行的资格,也不能转换到其他状态。
    


  • 5.线程的调度
  •  
  • 1. 线程的优先级
  •           Thread类的静态变量 
  •                      功能描述
    static int MAX_PRIORITY
    表示线程的最高优先级,相当于值10
    static int MIN_PRIORITY
    表示线程的最高优先级,相当于值1
    static int NORM_PRIORITY
    表示线程的最高优先级,相当于值5
    main线程具有普通的优先级,可以通过Thread类的setPriority(int newPriority)方法对其进行设置,该方法中的参数newPriority接受的1~10之间的整数或者Thread类的三个静态变量。
代码块解释:

class MaxPriority implement Runnable{
public void run(){
for(int i=0;i<10;i++){
    System.out.println(Thread.currentThread().getName()+"正在输出:"+i);
} } }
//定义类MINpriority实现Runnable接口
class MinPriority implements Runnable{
public void run(){
for(int i=0;i<10;i++)
{System.out.println(Thread.currentThread().getName()+"正在输入:"+i);
} } }
public class Example07{
public static void main(String[] args){
Thread minPriority=new Thread(new MinPriority(),"优先级较低的线程");
Thread maxPriority =new Thread(new MaxPriority(),"优先级较高的线程");
minPrioroty.setPriority(Thread.MIN_PRIORITY);//设置线程的优先级为1
maxPriototy,setPriority(Thread.MAX_PRIORITY);//设置线程的优先级为10
//开启两个线程
maxPriority.start();
minPriority.start();
}
    }
注意:有些操作系统并不是支持跟JAVA一样的优先级 记得不要太过依赖优先级,而只是把线程优先级作为一种提高程序效率的手段。
  • 2、线程休眠
            调用sleep(毫秒数)
代码块例子

public class xiumian {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        new Thread(new sleepThread()).start();
        for(int i=1;i<=10;i++)
        {
            if(i==5){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        // TODO 自动生成的 catch 块
                        e.printStackTrace();
                    }
            }
                System.out.println("主线程正在输出:"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
            }    }
            }
    }
class sleepThread implements Runnable{
    public void run(){
        for(int i=1;i<=10;i++)
        {
            if(i==3)
            {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
                System.out.println("线程--正在输出:"+i);
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }
        }}}

  • 3. 线程让步
线程让步:是用过用yield()方法来实现的,改方法跟sleep()方法有点类似,都可以让当前正在运行的线程暂停一下,区别在于yield()方法不会阻塞该线程,它只是将线程转换为就绪状态,让系统的调度器再一次重新调度一次。当某个线程调用yield()方法后,只有与当前线程优先级相同或者更高的线程才能获得执行的机会。
代码例子:
class YieldThread extends Thread{
    public YieldThread(String name){
    super(name);}
    public void run(){
        for(int i=0;i<5;i++){
        System.out.println(Thread.currentThread().getName()+"---"+i);
        if(i==3)
            System.out.print("线程让步:");
        Thread.yield();//线程运行到此,做出让步;
    }
    }
}
public class rangbu {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Thread t1=new YieldThread("线程A");
        Thread t2=new YieldThread("线程B");
        t1.start();
        t2.start();
    }
    }
  • 4线程插队
Thread类中join()方法来实现插队功能;
当某个线程中调用其他线程的join()方法时,调用的线程将被阻塞,直到被join()方法加入到线程执行完成后它才继续运行;
代码块示例:

public class chadui {
    public static void main(String[] args) throws Exception {
        // TODO 自动生成的方法存根
        Thread t=new Thread(new EmergencyThread(),"线程一");
        t.start();
        for(int i=1;i<6;i++)
        {
            System.out.println(Thread.currentThread().getName()+"输入:"+i);
            if(i==2)
            {
        t.join();//调用join()方法
                }
            Thread.sleep(500);
            }
    }

}
class EmergencyThread implements Runnable{
    public void run(){
        for(int i=1;i<6;i++)
    {
        System.out.println(Thread.currentThread().getName()+"输入:"+i);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }    }
}
  • 5.多线程同步
    控制在同个时刻只能被一个线程访问
     1.线程安全 同步:synchronized
代码示例:

public class tongbu {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        SalaThread salaThread=new SalaThread();
        new Thread(salaThread,"线程一").start();
        new Thread(salaThread,"线程二").start();
        new Thread(salaThread,"线程三").start();
        new Thread(salaThread,"线程四").start();
    }

}
class SalaThread implements Runnable{
    private int tickets=100;
    Object lock=new Object();
    public void run(){
        while(true){
            synchronized (lock) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
        if(tickets>0){
            System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
        }else
        {break;}
            }
    }
    }
}
注意:同步代码块中的锁对象可以是任意的类型对象,但是多个线程共享的锁对象必须是唯一的。“任意”说的是共享所对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位。线程之间便不能产生同步的效果。
  • 6.同步方法
    在方法前面同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能,具体语法格式如下:
synchronized 返回值类型 方法名([参数1,......]){ }
被synchronize修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,知道当前线程访问完毕后,其他线程才有机会执行方法。
代码块示例:
class DeadLockThread implements Runnable{
    static Object chopsticks=new Object(); //定义object类型的chopsticks锁对象
    static Object knifeAndFork=new Object();  //定义object类型的knifeAndFork锁对象
    private boolean flag;//定义boolean类型的变量flag
    DeadLockThread(boolean flag) {
    this.flag=flag;}
public void run(){
    if(flag){
    while(true){

            synchronized (chopsticks) {//chopsticks锁对象上的同步代码块
                System.out.println(Thread.currentThread().getName()+"---if---chopsticks");
                synchronized (knifeAndFork) {//knifeAndFork锁对象上的同步代码块
                    System.out.println(Thread.currentThread().getName()+"---if---knifeAndFork");
                }
            }
        }
    }
    else{
        while (true) {
            synchronized (knifeAndFork) {
                System.out.println(Thread.currentThread().getName()+"---else---knifeAndFork");

            synchronized (chopsticks) {
                System.out.println(Thread.currentThread().getName()+"---else---chopsticks");
            }
        }
    }
}
}
}
public class sisuo {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
//创建连个DeadLockThread对象
        DeadLockThread d1=new DeadLockThread(true);
        DeadLockThread d2=new DeadLockThread(false);
        //创建并开启两个线程
        new Thread(d1,"Chinese").start();
        new Thread(d2,"American").start();

    }

}
  • 7.多线程通信
示例代码:
class Input implements Runnable{
    private Storage  st;
    private int  num;

    Input(Storage st) {
        this.st=st;

    }
    public void run() {
        while(true){
            st.put(num++);
        }
    }
}

class output implements Runnable{
    private Storage st;
    output(Storage st){
        this.st=st;

    }
        public void run(){
            while(true)
                st.get();
        }
    }


 class Storage {
    //数据存储数组
    private int [] cells=new int[10];
    //inPos表示存入时数组的下标,outpos表示数组取出时数组的下标
    private int inPos,outPos,count;
    //定义一个put()方法向数组中存入数据
    public synchronized void put(int num){
        try {    
            while(count==cells.length)
            {
            this.wait();
        }
        cells[inPos]=num;
        System.out.println("在cells["+inPos+"]中放入数据---"+cells[inPos]);
        inPos++;    //存完元素让位置加1
        if(inPos==cells.length)
            inPos=0;//当inPos为数据长度时,将其置为0
        count++;
        this.notify();
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    //定义一个get()方法从数组中取出数据
    public synchronized void get()
    {
        try {
            while(count==0){
                this.wait();
            }
                int data =cells[outPos];
                System.out.println("从celss["+outPos+"]中取出数据"+data);
                outPos++;    //取完元素让位置加1
                if(outPos==cells.length)
                    outPos=0;
                count--;
                this.notify();
        } catch (Exception e) {
            // TODO: handle exception
        }


    }

}

public class yunxing {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Storage st=new Storage();
        Input input=new Input(st);
        output output=new output(st);
        new Thread(input).start();
        new Thread(output).start();
    }

}

0
0
查看评论

如何终止java线程

终止线程的三种方法      有三种方法可以使终止线程。      1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。      ...
  • anhuidelinger
  • anhuidelinger
  • 2013-09-16 19:51
  • 160122

linux下查看Java进程

为了方便我下次查找所以写了 这个博客记录下别人的 以下是别人的链接 一般简单使用 ps -ef | grep java netstat -ntpl http://www.jiacheo.org/blog/279 https://www.zhihu.com/question/202...
  • u013086392
  • u013086392
  • 2017-01-29 16:39
  • 3187

Java与线程

揭开java线程和操作系统线程之间的神秘面纱
  • lingdudebing
  • lingdudebing
  • 2016-03-08 03:21
  • 486

Java并发编程番外篇(一)如何结束一个线程

本篇博客介绍下如何结束一个线程。在Java 的设计中,当一个线程的run方法中代码执行结束后,该线程就自动结束了。但是,在我们的实际开发过程中,可能会需要手动的结束一个线程,此时我们应该怎么安全地结束一个线程呢?1. stop方法根据Java的官方文档,Java Thread,该方法已被弃用。文档给...
  • u014088294
  • u014088294
  • 2016-08-12 08:37
  • 641

java四种线程的使用

Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。...
  • w_wensan
  • w_wensan
  • 2017-04-12 14:31
  • 527

java中线程的基本操作!

java中建立线程可以有两种方式,分别是继承Thread类和实现Runnable接口. 1.继承Thread public class MyThread extends Thread{ public MyThread(String name){ super(name); } ...
  • kkkkkxiaofei
  • kkkkkxiaofei
  • 2013-10-11 16:44
  • 1871

Java最佳线程数

对于计算密集型任务,在拥有Ncpu个处理器的系统上,当线程池大小为N+1时,通常能实现最优的利用率,(即当计算密集型任务偶尔由于页缺失故障或者其他原因而暂停时,这个额外的现线程也能够确保CPU的时钟周期不会被浪费。)  对于包含IO操作或者其他阻塞操作的任务,由于线程并不会一直执行,...
  • cloudeagle_bupt
  • cloudeagle_bupt
  • 2017-04-05 16:26
  • 795

Java垃圾回收无效线程吗?

测试结果表明:线程在无效之后,GC会回收无效线程,参考附图由原先的18个线程编程12个线程 测试代码: public class ThreadTest { public static void main(String[] args) { ThreadTest threa...
  • tomli2017
  • tomli2017
  • 2017-04-16 17:18
  • 674

java线程常用方法详解

1、sleep() 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。 例如有两个线程同时执行(没有synchronized)一个线程优先级为M...
  • nan167567
  • nan167567
  • 2016-08-01 19:57
  • 4299

Java多线程的常用方法(命名与取得)

一、线程的命名与取得 所有的线程程序的执行,每一次都是不同的运行结果,如果要想区分每一个线程,那么久必须依靠线程的名字。对于线程的名字一般而言会在启动之前进程定义,不建议对已经启动的线程,进行更改名称,或者为不同线程设置重名的情况 如果要进行线程名称的操作,可以使用T...
  • wangdajiao
  • wangdajiao
  • 2016-07-26 21:40
  • 5777
    个人资料
    • 访问:1485次
    • 积分:84
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档