多线程(一)(主要关于API)(Java多线程编程核心技术)

最近在读java多线程编程核心技术,记录学习心得

实现多线程有两种:1.继承Thread类 2.实现Runnable接口

1.1继承Thread类

class Thread implements Runnable (Thread 继承了Runnable接口)

使用多线程技术时,代码运行结果与代码执行顺序或调用顺序是无关的.

1.2实现Runnable接口(如果已经有父类了,不能在继承Thread类,则实现Runnable接口)

把Thread类对象传入构造函数,可以实现将一个Thread对象的run方法交给其他的线程使用

public class CountOperate extends Thread{
    public CountOperate(){
        System.out.println("CountOperate---begin");
        System.out.println("Thread.currentThread().getName="+Thread.currentThread().getName());
        System.out.println("this.getName="+this.getName());
        System.out.println("CountOperate----end");
    }

    @Override
    public void run() {
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName="+Thread.currentThread().getName());
        System.out.println("this.getName="+this.getName());
        System.out.println("run----end");
    }
}

第一种:

public static void main(String[] args) {
        CountOperate c=new CountOperate();
        Thread t1=new Thread("A");
        t1.start();
        /*output:
            CountOperate---begin
            Thread.currentThread().getName=main
            this.getName=Thread-0
            CountOperate----end
        */
    }

是main线程执行构造函数(ps:这个main和main方法没关系,只不过名字相同)

第二种:

public static void main(String[] args) {
        CountOperate c=new CountOperate();
        Thread t1=new Thread(c,"A");
        t1.start();
        /*
         CountOperate---begin
         Thread.currentThread().getName=main
         this.getName=Thread-0
         CountOperate----end
         run---begin
         Thread.currentThread().getName=A
         this.getName=Thread-0
         run----end
        */
    }

main线程执行构造方法,start()会自动调用run方法

2 实例变量与线程安全

这里就涉及到一个线程安全的问题了.

public class MyThread extends Thread{
    private int count=5;

    @Override
    public void run() {
        super.run();
        count--;
        System.out.println("由"+Thread.currentThread().getName()+"计算 count="+count);
    }
}
public static void main(String[] args) {
    MyThread myThread=new MyThread();
    Thread a=new Thread(myThread,"a");
    Thread b=new Thread(myThread,"b");
    Thread c=new Thread(myThread,"c");
    Thread d=new Thread(myThread,"d");
    Thread e=new Thread(myThread,"e");
    a.start();
    b.start();
    c.start();
    d.start();
    e.start();
    /*output:
    由a计算 count=2
    由c计算 count=2
    由d计算 count=1
    由b计算 count=2
    由e计算 count=0
     */
}

原因:i--,分为3步4, 1)取得原有的i值 2)计算i-1 3)对i进行赋值 同时访问i值,就会产生非线程安全问题

解决方法:在run方法synchronized 关键字

3.Thread currentThread():获取当前线程对象

boolean siAlive():判断当前的进程是否处于活动状态

String getId() 获取线程的唯一标识

4.线程中断

interrupt():停止线程

interrupted():判断当前线程是否已经中断

isInterrupted():测试线程是否已经中断

ps:比较interrupted()方法和isInterrupted()方法?

从源码看:

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

举个例子我们能更好理解:

//线程类
public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i = 0; i <50000; i++) {
            System.out.println("i="+(i+1));
        }
    }
}
//测试类
public class Run2 {
    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        System.out.println("是否停止1?="+Thread.interrupted());
        System.out.println("是否停止2?="+Thread.interrupted());
    }
    /*output:
        是否停止1?=true
        是否停止2?=false
    */
}

原因:interrupted()方法具有清除状态的功能

ps:native修饰方法

public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}
private native void interrupt0();

native修饰方法,表示调用的是原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中.

public boolean isInterrupted() {
    return isInterrupted(false);
}

例子:

public static void main(String[] args) {
    try {
        MyThread myThread=new MyThread();
        myThread.start();
        myThread.sleep(1000);
        myThread.interrupt();
        System.out.println("是否停止1?="+myThread.isInterrupted());
        System.out.println("是否停止2?="+myThread.isInterrupted());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("end!");
}
/*取打印结果:
是否停止1?=false
是否停止2?=false
end!
*/

isInterrupted()测试线程对象是否已经是中断状态,但不清除状态标志.

5.在沉睡中停止:

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            System.out.println("线程1="+Thread.currentThread().getName());
            Thread.sleep(200000);
            System.out.println("run end");
        } catch (InterruptedException e) {
            System.out.println("在沉睡中停止!进入catch!");
            e.printStackTrace();
        }
    }
}
public static void main(String[] args) {
        MyThread thread =new MyThread();
        try {
            thread.start();
            System.out.println("线程2="+Thread.currentThread().getName());
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end!");
}
/*
output:
线程2=main
run begin
线程1=Thread-0
end!
在沉睡中停止!进入catch!
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at us.codecraft.tinyioc.MyThread.run(MyThread.java:59)
*/
    }

stop() 包里停止线程,但是可能会造成数据不一致的结果,不建议使用

使用return 停止线程

while (true) {
    if (Thread.interrupted()) {
        System.out.println("停止了");
        return;
    }
    System.out.println(System.currentTimeMillis());
}

6.暂停线程

suspend()(暂停线程)和resume()(重启线程)方法

缺点:

(1).独占,如果使用不当会,会造成公共的同步对象的独占,使其他线程无法访问公共同步对象

(2).不同步

7.yield():放弃当前的cpu资源,将他让给其他的任务去占用cpu执行时间,但放弃的时间不确定,有可能刚刚放弃,马上又获取cpu时间片

@Override
public void run() {
    long beginTime=System.currentTimeMillis();
    int count =0;
    for (int i = 0; i <5000000 ; i++) {
        //Thread.yield();
        count=count+(i+1);
    }
    long endTime=System.currentTimeMillis();
    System.out.println("用时:"+(endTime-beginTime)+"毫秒");
}
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
/*output:用时:11毫秒*/
//去掉Thread.yield()
/*用时:453毫秒*/
}

8.线程的优先级 setPriority()

public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    //线程优先级分为1-10,如果小于1大于10 则抛出异常
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
    //如果设置权限登记大于线程组的最大等级,就将设置权限设为线程租最大等级
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

优先级可以被继承(此继承非彼继承),比如由A线程启动B线程,B线程的优先级与A是一样的

8 优先级具有规则性

public class MyThread1 extends Thread{
    @Override
    public void run() {
       long beginTime=System.currentTimeMillis();
       long addResult=0;
       for(int j = 0; j <10; j++){
            //业务逻辑
           for (int i = 0; i <50000; i++) {
               Random random=new Random();
               random.nextInt();
               addResult=addResult+i;
           }
       }

        long endTime=System.currentTimeMillis();
        System.out.println("***** thread 1 use time ="+(endTime-beginTime));
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run() {
        long beginTime=System.currentTimeMillis();
        long addResult=0;
        for (int i = 0; i <10; i++) {
            //业务逻辑
            for (int j = 0; j <50000; j++) {
                Random random=new Random();
                random.nextInt();
                addResult=addResult+i;
            }
        }
        long endTime=System.currentTimeMillis();
        System.out.println("***** thread 2 use time ="+(endTime-beginTime));
    }
}
public class Run {
    public static void main(String[] args) {
        for (int i = 0; i <5 ; i++) {
            MyThread1 thread1=new MyThread1();
            thread1.setPriority(1);
            thread1.start();
            MyThread2 thread2=new MyThread2();
            thread2.setPriority(10);
            thread2.start();
        }
    }
}

结果:

//***** thread 2 use time =130  ***** thread 2 use time =263    ***** thread 2 use time =279
//***** thread 2 use time =156  ***** thread 2 use time =284    ***** thread 2 use time =328
//***** thread 1 use time =248  ***** thread 1 use time =292    ***** thread 2 use time =364
//***** thread 2 use time =355  ***** thread 1 use time =315    ***** thread 1 use time =393
//***** thread 1 use time =370  ***** thread 1 use time =334    ***** thread 1 use time =351
//***** thread 2 use time =387  ***** thread 1 use time =370    ***** thread 2 use time =433
//***** thread 2 use time =396  ***** thread 2 use time =428    ***** thread 1 use time =437
//***** thread 1 use time =397  ***** thread 2 use time =433    ***** thread 2 use time =440
//***** thread 1 use time =431  ***** thread 1 use time =402    ***** thread 1 use time =440
//***** thread 1 use time =455  ***** thread 2 use time =447    ***** thread 1 use time =443

总结:这是3次执行结果,我们发现,优先级较高则优先执行完run()方法中的任务,但这个结果不能说的太肯定,因为优先级还具有随机性(第二列),也就是优先级高的线程不一定每一次都先执行完.

也就是说优先级高的获取cpu资源的概率大,但是有时候概率低的也有可能先执行完.

9守护线程

线程有两种,第一种是用户线程,第二种是守护线程(例如垃圾回收器)

如果没有非守护线程,则守护线程自动销毁

例子:

public class MyThread extends Thread{
    private int i=0;
    @Override
    public void run() {

        try {
            while (true) {
                i++;
                System.out.println("i=" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) {
        try {
            MyThread thread=new MyThread();
            //设置为守护线程
            thread.setDaemon(true);
            thread.start();
            Thread.sleep(5000);
            //主线程沉睡,守护线程离开thread对象不再打印
            System.out.println("我离开thread对象就不再打印了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*output:
    i=1
    i=2
    i=3
    i=4
    i=5
    我离开thread对象就不再打印了
    i=6
    */
}

猜你喜欢

转载自my.oschina.net/u/3744319/blog/1600758
今日推荐