线程

时间:2022-06-19
本文章向大家介绍线程,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

添加描述

添加描述

添加描述

添加描述

Run() start的区别

添加描述

添加描述

添加描述

添加描述

class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

添加描述

一、通过构造方法传递数据

在创建线程时,必须要建立一个Thread类的或其子类的实例。因此,我们不难想到在调用start方法之前通过线程类的构造方法将数据传入线程。并将传入的数据使用类变量保存起来,以便线程使用(其实就是在run方法中使用)。下面的代码演示了如何通过构造方法来传递数据:

package mythread;

public class MyThread1 extends Thread
{
   private String name;
   public MyThread1(String name)
   {
       this.name = name;
   }
    public void run()
    {
        System.out.println("hello " + name);
    }
    public static void main(String[] args)
    {
        Thread thread = new MyThread1("world");
      thread.start();
   }
}

由于这种方法是在创建线程对象的同时传递数据的,因此,在线程运行之前这些数据就就已经到位了,这样就不会造成数据在线程运行后才传入的现象。如果要传递更复杂的数据,可以使用集合、类等数据结构。使用构造方法来传递数据虽然比较安全,但如果要传递的数据比较多时,就会造成很多不便。由于Java没有默认参数,要想实现类似默认参数的效果,就得使用重载,这样不但使构造方法本身过于复杂,又会使构造方法在数量上大增。因此,要想避免这种情况,就得通过类方法或类变量来传递数据。

二、通过变量和方法传递数据

向对象中传入数据一般有两次机会,第一次机会是在建立对象时通过构造方法将数据传入,另外一次机会就是在类中定义一系列的public的方法或变量(也可称之为字段)。然后在建立完对象后,通过对象实例逐个赋值。下面的代码是对MyThread1类的改版,使用了一个setName方法来设置name变量:

package mythread;

public class MyThread2 implements Runnable

{
    private String name;
    public void setName(String name)
    {

        this.name = name;
    }
    public void run()
   {
       System.out.println("hello " + name);
    }

    public static void main(String[] args)
    {
         MyThread2 myThread = new MyThread2();
         myThread.setName("world");
         Thread thread = new Thread(myThread);
          thread.start();

   }

}

https://www.cnblogs.com/wihainan/p/4765862.html

sleep()不会释放锁

B进入锁池 A进入等待池中

锁池和等待池都是针对对象而言

  private volatile boolean go = false;
    public static void main(String args[]) throws InterruptedException {
        final NotificationDemo test = new NotificationDemo();

        Runnable waitTask = new Runnable(){

            @Override
            public void run(){
                try {
                    test.shouldGo();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " finished Execution");
            }
        };

        Runnable notifyTask = new Runnable(){

            @Override
            public void run(){
                test.go();
                System.out.println(Thread.currentThread().getName() + " finished Execution");
            }
        };

        Thread t1 = new Thread(waitTask, "WT1"); //will wait
        Thread t2 = new Thread(waitTask, "WT2"); //will wait
        Thread t3 = new Thread(waitTask, "WT3"); //will wait
        Thread t4 = new Thread(notifyTask,"NT1"); //will notify

        //starting all waiting thread
        t1.start();
        t2.start();
        t3.start();

        //pause to ensure all waiting thread started successfully
        Thread.sleep(200);

        //starting notifying thread
        t4.start();

    }
    /*
     * wait and notify can only be called from synchronized method or bock
     */
    private synchronized void shouldGo() throws InterruptedException {
        while(go != true){
            System.out.println(Thread.currentThread()
                    + " is going to wait on this object");
            wait(); //release lock and reacquires on wakeup
            System.out.println(Thread.currentThread() + " is woken up");
        }
        go = false; //resetting condition
    }

    /*
     * both shouldGo() and go() are locked on current object referenced by "this" keyword
     */
    private synchronized void go() {
        while (go == false){
            System.out.println(Thread.currentThread()
                    + " is going to notify all or one thread waiting on this object");

            go = true;   //making condition true for waiting thread
            notify();  // only one out of three waiting thread WT1, WT2,WT3 will woke up
            //notifyAll(); // all waiting thread  WT1, WT2,WT3 will woke up
        }

    }
Thread[WT2,5,main] is going to wait on this object
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
NT1 finished Execution
Thread[WT2,5,main] is woken up
WT2 finished Execution

只是暗示并不是强制

Thread.yield(); 对锁没有影响  并不会让出锁

非常暴力 不安全

public static void main(String[] args) throws InterruptedException {
    Runnable interruptTask = new Runnable() {
        @Override
        public void run() {
            int i = 0;
            try {
                //在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程
                while (!Thread.currentThread().isInterrupted()) {
                    Thread.sleep(100); // 休眠100ms
                    i++;
                    System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i);
                }
            } catch (InterruptedException e) {
                //在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)
                System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException.");
            }
        }
    };
    Thread t1 = new Thread(interruptTask, "t1");
    System.out.println(t1.getName() +" ("+t1.getState()+") is new.");

    t1.start();                      // 启动“线程t1”
    System.out.println(t1.getName() +" ("+t1.getState()+") is started.");

    // 主线程休眠300ms,然后主线程给t1发“中断”指令。
    Thread.sleep(300);
    t1.interrupt();
    System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");

    // 主线程休眠300ms,然后查看t1的状态。
    Thread.sleep(300);
    System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
}

http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/

在解释轻量级锁的执行过程之前,先明白一点,轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁

局部变量:线程安全

        每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。

如何理解上面这句话:

        局部变量(方法内部的私有变量)是线程安全的,如下段代码中的num这个私有变量是线程安全的,原因是在new HasSelfPrevateNum()这个类的时候它只会为类中的属性成员变量开辟空间,而方法只在方法区开辟一个内存空间并且只存一份是共用的代码段(变量在堆区,引用在栈区),而方法中的私有变量不会先开辟出内存空间,而是等调用时在对应调用线程中为方法中的变量申请空间,所以有几个线程调用则每个线程就会在自己的线程空间的栈为局部变量申请几个引用同时在堆中为变量再申请对应的空间(即方法内的私有变量有几个线程就在栈中申请几个引用,在堆中申请几个空间),所以多线程在调用时只会处理自己线程内的方法的私有变量,因此,方法内的私有变量是线程安全的。

如:

public class HasSelfPrivateNum {
    
    public void addI(String username)
    {
        try
        {
            int num = 0;
            if(username.equals("a"))
            {
                num = 100;
                System.out.println("a set over !");
                Thread.sleep(2000);
            }
            else
            {
                num = 200;
                System.out.println("b set over !");
            }
            System.out.println(username + " num = " + num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}