java多线程——java中进程与线程的操作、关系以及创建线程的三种方式

类似于操作系统中的概念,每个线程都是共享其隶属的进程空间,如堆、方法区,
但是同时,每一个线程还是有一点属于自己的资源:程序计数器以及方法栈。

在java的线程设计中,start方法只是使得线程处于就绪状态,只有当执行了run方法才获取cpu控制器、才处于真正的执行状态。
但是一般来说,线程之间都是时间片调度,所以即使run(或者call)方法与start方法是绑定一起执行的,但是run方法一般都是滞后于start方法。


java中的PV操作:
最基本的是使用notify、synchronized以及wait方法来实现。
其中,synchronized关键字可以加在实体对象上(类似try),也可以加在方法上:

synchronized(实体){
    if(条件不足)
        实体.wait();
}

synchronized void method(){
    do something
}
当一个实体处于wait时,一般情况下都是需要其他实体通过调用notifyAll方法通知而解除wait状态
在方法上加synchronized关键字时,不需要手动调用wait,也不需要其他实体调用notify,jvm自动调用。

以生产者消费者为例:
现在有一个生产者消费者公用队列queue
生产者:
synchronized(queue){
    while(queue是满的){
        //先放弃对queue的锁。然后:
        queue.wait();
    }
    //此时队列不满
    queue.add(obj);  //生产
    queue.notifyAll()  //发出通知。通知所有的被处于wait态的实体。相当于V操作
}

消费者:
synchronized(queue){
    while(queue是空的){
        //先放弃对queue的锁。然后线程本身等待
        queue.wait();
    }
    //队列不为空
    queue.get(obj);  //消费
    queue.notifyAll()  //发出通知
}


当线程被wait()阻塞后,只是剩下wait()语句出现之后的代码段还未执行。
    当被唤醒时,线程会从wait()语句下一条语句开始执行。
    也就是说线程被阻塞的时候,同时保存了执行点情况
    可也是为什么,notify/notifyAll需要搭配synchronized一起使用

线程的interrupt()方法与isInterrupted()方法:
首先,interrupt()方法内部是通过调用isInterrupted()方法实现,并且:
如果当前线程是阻塞的,调用isInterrupted()方法时理所当然是返回:true;反之false。
而如果当前线程是阻塞的,而且调用interrupt()方法,则会返回:false。
因为:interrupt()方法会改变线程阻塞状态:阻塞态调用则转为就绪唤醒态;反之亦然。即:
interrupt()方法会清除中断标志。


小技巧:
在命令行中使用:jps 命令查看当前在jvm中运行的进程(一般是用户进程)。
普通的ThreadLocal与inheritableThreadLocal之间的异同:
首先,两者都是线程内部的域,每一个线程都有,且私有。
这个私有、同级线程之间都不一样是通过设置值的时候实现的:
通过源码以及继承关系知道,不管是ThreadLocal,还是inheritableThreadLocal,都是一个ThreadLocals的映射,
而这个ThreadLocals底层是由一个特殊哈希函数的HashMap实现的。
而在设置值的时候,key是传入的Thread的引用,value是泛型T。
所以,通过由这个引用设置的key,从而达到私有的目的,这也是ThreadLocal的思路。

但是,如果想要使得子线程像共享父进程(线程)资源那样,共享父线程的ThreadLocals,则需要通过inheritableThreadLocal来实现。
其实inheritableThreadLocal与ThreadLocal的差距就在线程创建的本身:
通过阅读源码可以看到,创建子线程的时候,通过线程的构造函数,先检查父线程的inheritableThreadLocal的有无,
如果不为null,则将子线程的inheritableThreadLocal设置为:
this.inheritableThreadLocal = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals)
其中,parent是父线程。
通过ThreadLocal的静态方法:createInheritedMap()来为子线程的inheritableThreadLocal域赋值,相当于复制。
createInheritedMap()方法:
createInheritedMap(ThreadLocalMap parentMap){
    return new ThreadLocalMap(parentMap);
}
可以看出,这种复制是值的复制,而不是引用复制。


第一种:继承Thread类

package createThreadMethod;


//使用继承Thread类的方法实现创建线程的目的。
//优点是:比较简单,可以在自定义Thread子类中添加各种域以及方法。
//缺点是:①执行任务单一。线程本身与线程要执行的任务硬绑定。
//        ②无返回值
public class OneThread extends Thread{
    @Override
    public void run() {
        System.out.println("the first method that create the multiThread.....");
    }

    public static void main(String []args){

        Thread oneThread = new OneThread();
        oneThread.start();
    }
}

第二种:实现Runnable接口

package createThreadMethod;/*
name: TwoThread
user: ly
Date: 2020/5/29
Time: 11:16
*/
//使用实现Runnable接口来创建多线程
//优点为:线程本身与线程执行的任务彻底分离。
//缺点也很明显:无返回值。

public class TwoThread {

    public static class RunnableTask implements Runnable{
        public void run() {
            System.out.println("the second method that create the multiThread.....");
        }
    }

    public static void main(String []args){
        Runnable task1 = new RunnableTask();
        Runnable task2 = new RunnableTask();

        new Thread(task1).start();
        new Thread(task2).start();
    }

}

第三种:实现callable接口,并使用futureTask实现

package createThreadMethod;/*
name: ThirdThread
user: ly
Date: 2020/5/29
Time: 11:36
*/

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThirdThread{
    public static class MyCallableTask implements Callable{
        public Object call() throws Exception {   //注意第三种方法与前面两种的差别:重写run方法 VS 重写call方法
            return "\"the third method that create the multiThread.....\"";
        }
    }
    public static void main(String []args){
        //使用FutureTask(与第二种方法--使用Runnable的不同
        FutureTask<String> futureTask = new FutureTask<String>(new MyCallableTask());

        //先启动。但是此时该线程不一定立即执行
        new Thread(futureTask).start();
        try{
            //此时等待执行,并且从线程执行的任务:MycallableTask中可以看到,线程执行后会返回一个Object,这里定义为String
            String result = futureTask.get();
            System.out.println(result);
        }catch (ExecutionException e){
            e.printStackTrace();
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

最后是一些java中实现的进程、线程与传统操作系统理论中的差异:

synchronized与wait(即java中的PV操作)

package createThreadMethod;/*
name: demo01
user: ly
Date: 2020/5/29
Time: 14:08
*/
/测试:synchronized与wait(即java中的PV操作)
public class demo01 {

    static volatile Object obj1 = new Object();
    static volatile Object obj2 = new Object();

    public static void main(String []args) throws InterruptedException{
        test4();
    }
    //会死锁  说明:即使obj2是在obj1内部获取的,当调用obj1.wait()使得obj1的锁释放时,obj2的锁不会也跟随释放,除非手动释放。
    public static void test1() throws InterruptedException{
        //创建两个线程
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                try{
                    //先获取obj1
                    synchronized (obj1){
                        System.out.println("threadA get the resource1's lock...");

                        //再尝试获取obj2
                        synchronized (obj2){
                            System.out.println("threadA get the resource2'lock...");

                            //再释放obj1的锁
                            System.out.println("threadA release the resource1' lock");
                            obj1.wait();

                        }
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });

        //创建另一个线程
        Thread threadB = new Thread(new Runnable() {
            public void run() {
                try{
                    //先休眠1s。让threadA先获取object
                    Thread.sleep(1000);
                    //再尝试去获取OBJ1
                    synchronized (obj1){
                        System.out.println("threadB get the resource1's lock...");
//                       拿到object1的锁后
                        //然后再尝试拿到object2的锁
                        synchronized (obj2){  //应该是拿不到的。因为threadA没有释放
                            System.out.println("threadB get the resource2's lock...");
                            //再释放object1
                            System.out.println("threadB release the resource1's lock");  //应该是放不了
                            obj1.wait();
                        }
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        //启动两个线程
        threadA.start();
        threadB.start();
        //等待线程结束
        threadA.join();
        threadB.join();
        System.out.println("main thread is over...");
    }

    //阻塞后中断
    public static void test2() throws InterruptedException{
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try{
                    System.out.println("----begin-----");
                    synchronized (obj1){
                        obj1.wait();   //自己阻塞自己
                    }
                    System.out.println("----end----");
                }catch (InterruptedException e){
                    System.out.println("interrupt...");
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        Thread.sleep(2000);
        System.out.println("----begin interrupt sub thread");
        thread.interrupt();
        System.out.println("----end interrupt sub thread");
    }

    public static void test3() throws InterruptedException{
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                //先获取obj1
                try{
                    synchronized (obj1){
                        System.out.println("threadA get the obj1 lock");
                        Thread.sleep(1000);
                        synchronized (obj2){
                            System.out.println("threadA get the obj2 lock");

                        }
                        System.out.println("threadA release the obj2 lock");
//                        obj2.notify();
                    }
//                    obj1.notify();
                    System.out.println("threadA release the obj1 lock");
                }catch (Exception e){

                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            public void run() {
                //先获取obj1
                try {
//                    Thread.sleep(500);
                    synchronized (obj1) {
                        System.out.println("threadB get the obj1 lock");
                        synchronized (obj2) {
                            System.out.println("threadB get the obj2 lock");
//                            obj2.notify();
                        }
//                        obj2.notifyAll();
                        System.out.println("threadB release the obj2 lock");
                    }
                    System.out.println("threadB release the obj1 lock");
//                    obj1.notify();

                } catch (Exception e) {

                }

            }
        });

        threadA.start();
        threadB.start();

        threadA.join();
        threadB.join();
        System.out.println("main thread is over...");
    }

    /*
    这个例子证明:当线程被wait()阻塞后,只是剩下wait()语句出现之后的代码段还未执行。
    当被唤醒时,线程会从wait()语句下一条语句开始执行。
    也就是说阻塞的时候,保存了执行点情况
    可也是为什么,notify/notifyAll需要搭配synchronized一起使用
    */
    public static void test4() throws InterruptedException{
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                try{
                    synchronized (obj1){
                        System.out.println("此时获得obj1的公用监视器锁");
                        System.out.println("我还要等别人叫我...");
                        //再将自己挂到obj1 的阻塞队列上。
//                        但是此时会自动释放公用监视器锁
                        obj1.wait();
                        System.out.println("我被唤醒了...");
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            public void run() {
                try{
                    synchronized (obj2){
                        System.out.println("此时获得obj2的公用监视器锁");
//                        obj1.notifyAll();   //这样肯定报错。因为此线程获取的并不是obj1的监视器锁
                    }
                    System.out.println("threadB is over");
                    synchronized (obj1){
                        System.out.println("唤醒阻塞在obj1上的所有阻塞线程");
                        obj1.notifyAll();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

        threadA.start();
        threadB.start();

        threadA.join();
        threadB.join();
        System.out.println("over...");
    }
}

线程sleep

package createThreadMethod;/*
name: demo02
user: ly
Date: 2020/5/29
Time: 15:26
*/
//该demo用于说明:当线程sleep的时候并不会放弃锁
//tips:   yield方法与sleep方法类似。差别在于:
//    yield方法调用后,当前线程让出CPU,即使当前线程还有时间片未用完。
//    此时系统再次调度。此时可能会再次调度到刚刚使用yield方法的那个线程。
//    而使用sleep时,当前线程也放弃CPU处于就绪态,但是直到sleep时间结束前都不会被调度到
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class demo02 {
    static final Lock lock = new ReentrantLock();
    static final Object obj1 = new Object();

    public static void main(String []args){
        test1();
        test2();
    }

    //测试:sleep时是否会释放普通lock
    public static void test1(){
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                //先拿到锁
                System.out.println("threadA get the lock");
                lock.lock();
                try{
                    System.out.println("threadA is sleeping....");
                    Thread.sleep(10000);
                    System.out.println("threadA is awaking");
                }catch (InterruptedException e){
                    e.printStackTrace();
                }finally {
                    System.out.println("threadA release the lock");
                    lock.unlock();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            public void run() {
                System.out.println("threadB get the lock");
                //会等待10秒
                lock.lock();
                try{
                    System.out.println("threadB is sleeping....");
                    Thread.sleep(10000);
                    System.out.println("threadB is awaking");
                }catch (InterruptedException e){
                    e.printStackTrace();
                }finally {
                    System.out.println("threadB release the lock");
                    lock.unlock();
                }
            }
        });

        threadA.start();
        threadB.start();
        System.out.println("haven't the function join, the main thread is over firstly");
    }

    //测试:sleep时是否会释放监视器锁
    public static void test2(){
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                System.out.println("threadA getting the monitor lock");
                try{
                    synchronized (obj1){
                        System.out.println("threadA is sleeping");
                        Thread.sleep(5000);
                        System.out.println("threadA is awaking");
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            public void run() {
                System.out.println("threadB getting the monitor lock");
                try{
                    synchronized (obj1){
                        System.out.println("threadBis sleeping");
//                        Thread.sleep(5000);
                        System.out.println("threadB is awaking");
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

        threadA.start();
        threadB.start();
        System.out.println("haven't the function join, the main thread is over firstly");
    }

}

死锁

package createThreadMethod;/*
name: demo03
user: ly
Date: 2020/5/29
Time: 16:10
*/


import org.omg.CORBA.INITIALIZE;

//  该demo用于示例: 死锁。
public class demo03 {
    private static Object object1 = new Object();
    private static Object object2 = new Object();

    public static void main(String []args){
        Thread threadA = new Thread(new Runnable() {
            public void run() {
                try{
                    System.out.println("threadA is getting the object1...");
                    synchronized (object1){
                        System.out.println("threadA get the object1!");
                        System.out.println("threadA is getting the object2...");
                        Thread.sleep(2000);  //睡眠,以便在当前线程获取object2之前,另一个线程就将其占据
                        //睡眠后获取object2
                        synchronized (object2){
                            System.out.println("threadA get the object2!");
                        }
                    }
                }catch (InterruptedException e){
                    System.out.println("threadA is interrupted when it is sleeping or waitting...");
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            public void run() {
                try{
                    System.out.println("threadB is getting the object2...");
                    synchronized (object2){
                        System.out.println("threadB get the object2!");
                        System.out.println("threadB is getting the object1...");
                        Thread.sleep(2000);  //睡眠,
                        //睡眠后获取object1
                        synchronized (object1){
                            System.out.println("threadB get the object1!");
                        }
                    }
                }catch (InterruptedException e){
                    System.out.println("threadB is interrupted when it is sleeping or waitting...");
                }
            }
        });

        threadA.start();
        threadB.start();

        System.out.println("the main thread is over when it is not use the function join");


    }

}

④ ThreadLocal变量与 inheritanceThreadLcoal之间的区别

package createThreadMethod;/*
name: demo04
user: ly
Date: 2020/5/29
Time: 16:47
*/
//   本实例用于:展示普通的ThreadLocal变量与 inheritanceThreadLcoal之间的区别
public class demo04 {

    private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
    private static InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
    public static void main(String []args){
//        ordinaryThreadLocal();

        inheritanceThreadLocal();
    }

    public static void ordinaryThreadLocal(){
        threadLocal.set("the mainThread value");
        Thread thread = new Thread(new Runnable() {
            public void run() {
                //尝试在子线程中获取父线程中的、不可继承ThreadLocal线程变量
                System.out.println(Thread.currentThread()+":"+threadLocal.get());
            }
        });
        thread.start();
        //再尝试在主线程中获取。以做对比
        System.out.println(Thread.currentThread()+":"+threadLocal.get());
    }
    public static void inheritanceThreadLocal(){


        inheritableThreadLocal.set("the mainThread value");
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try{

                    Thread.sleep(2000);
                    //尝试在子线程中获取父线程中的、不可继承ThreadLocal线程变量
                    System.out.println(Thread.currentThread()+":"+inheritableThreadLocal.get());
                }catch(InterruptedException e){

                }
            }
        });
        thread.start();
        //再尝试在主线程中获取。以做对比
//        inheritableThreadLocal.set("another main value");    //用这个语句可以看出:这个复制是值的复制,而非引用。
        System.out.println(Thread.currentThread()+":"+inheritableThreadLocal.get());
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值