java多线程

package object;
/*
                多线程
    1、什么是进程?什么是线程?
        1.1进程是一个完整独立的程序(独立的代码与独立的数据空间)(资源调配)
        1.2线程是进程的一个执行单元(共享的代码与共享的数据空间)(cpu调度)

    2、线程内存分析
        2.1共享方法区、堆内存
        2.2独立一个栈
        2.3每个栈与每个栈之间互不干扰,各自执行各自目的

    3、主线程
        3.1在java中每次程序至少启动三个线程,一个是main主线程一个是垃圾收集线程一个是异常进程
        java命令执行一个类的时候,实际上都会启动一个JVM,每个JVM实际就是在
        操作系统启动了一个进程

    4、线程状态
                        (sleep\join\Thread.sleep()\.join())   阻塞状态    (run()\main())结束
                 1.Thread类(new Thread)——>初始状态(start()\Thread.yield())——>可运行       运行中
                            (synchronized\notify()\notifyAll()) 锁池状态    等待队列(wait())
      4.1新建状态:新创建一个线程对象
      4.2就绪状态:线程对象调用start()方法,状态变为可运行,等待cpu使用权
      4.3运行状态:就绪状态线程获得cpu使用,执行代码
      4.4阻塞状态:放弃cpu使用权,暂时停止运行。知道程序进入就绪状态才有机会运行
        4.4.1等待阻塞:线程执行wait(),JVM把该线程放入等待池中(会释放现有的锁)
        4.4.2同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
        4.4.3其他阻塞:线程执行sleep()/join()方法或者发出I/O请求,JVM就会将
        该线程变为阻塞状态,当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,
        线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
      4.5死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期

     5、线程调度
         5.1Java线程有优先级,优先级高的线程会获得较多的运行机会。(概率)
         5.2取值范围是1~10,Thread类有以下三个静态常量:
             static int MAX_PRIORITY(10)
             static int MIN_PRIORITY(1)
             static int NORM_PRIORITY(5)
         5.3Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
 每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。
————————————————
版权声明:本文为CSDN博主「Evankaka」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Evankaka/article/details/44153709




                                                                                                   @@ 思考一个问题
     6、线程实现方式                                                                       使用了多线程机制之后main方法结束,有可能程序不会结束ma
                                                                                     答:main方法结束只是主线程结束了,其他的线程可能还在压栈
     6.1:方式一通过继承Thread类,重写、创建子类对象、调用start()
     6.2:方式二通过Runnable接口,重写、创建Thread对象、调用start()
          也可以通过匿名内部类
          名内部类创建,创建Thread对象(Runnable接口参数)、重写、调用start()
     6.3:只有start才启动进程,run不能
          一个对象一个进程


     7、获取当前线程对象、获取线程对象名字、修改线程对象名字
                 方法名	                     作用
            static Thread currentThread()	获取当前线程对象
            String getName()	            获取线程对象名字
            void setName(String name)	    修改线程对象名字

     8、线程的分类:守护线程与用户线程
     thread.setDaemon(true)改为守护


     9、Thread与Runnable的区别
     9.1Thread继承一个类不适合使用资源共享,Runnable实现一个接口适合资源共享
     9.2Runnable的优势
        1)适合多个相同的代码程序的线程去处理同一个资源
        2)避免单继承的限制
        3)代码可以被多个线程共享,代码与数据独立,增加层序健壮性
        4)线程池的使用只能放入Runnable或callable类线程不能直接放入继承Thread类
     9.3**对于Thread继承需要共享数据时,建议使用类单例模式
     PS:两个关键点:1、单例;2、类属性(非实例属性)在类本身创建类属性,并通过构造器进行初始化
     9.4相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
          目前两种方式,要想启动线程,都是调用的Thread类中的start()。
 */
public class Threads {
    public static void main(String[] args) throws InterruptedException {
     //1、方式一通过继承Thread类,重写、创建子类对象、调用start()
     ThreadTest01 test01=new ThreadTest01();
    // test01.run();//不会启动线程,不会分配新的分支栈。(这种方式就是单线程。)
     test01.start();//启动

       // System.out.println(test01.currentThread());
    Thread.sleep(10000);
    Thread.interrupted();
     //2、方式二通过Runnable接口,重写、创建Thread对象、调用start()
     Thread test02=new Thread(new ThreadTest02());
     test02.start();

       // System.out.println(test02.getName());
     //3、方式三匿名内部类创建,创建Thread对象、重写、调用start()
     Thread test03=new Thread(new Runnable() {
         @Override
         public void run() {
            for (int i=0;i<100;i++)
                System.out.println("3");
         }
     });
        test03.start();


       //test03.setName("糕糕糕");

       // System.out.println(Thread.currentThread()+ test03.getName());
    }
}
class ThreadTest01 extends Thread
{
    @Override
    public void run() {
        for (int i=0;i<100;i++)
        {


            System.out.println("1");

        }


    }
}

class ThreadTest02 implements Runnable
{

    @Override
    public void run() {
        synchronized (this)
        {

        }
        for (int i=0;i<100;i++)
            System.out.println("2");
    }
}
class test00
{
    private String a;
    public test00(String a)
    {
        this.a=a;
    }
}
package object;

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

import static java.lang.Thread.sleep;
import static java.lang.Thread.yield;

/*
PS:关于run()方法小知识点
为什么run()方法只能try...catch...不能throws
因为run()方法在父类中没有抛出异常,子类不能比父类抛出更多的异常

                关于线程方法
      1、关于线程的sleep方法、、
          1.静态方法:Thread.sleep()
          2.参数是毫秒
          3.作用:让当前线程进入阻塞状态,放弃占有CPU时间片,
          当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
          4.不释放锁

      2、关于线程中断sleep方法interrupt
          1)实例方法:void interrupt()
          2)作用终止线程睡眠
          3)中断th线程的睡眠(这种中断睡眠的方式依靠了Java的异常处理机制)
          使得后面的代码无法执行,但可以使用finnally
          4)不要以为它是中断某个线程!它只是线线程发送一个中断信号,
          让线程在无限等待时(如死锁时)能抛出抛出,从而结束线程,
          但是如果你吃掉了这个异常,那么这个线程还是不会中断的!


      3、关于线程的yield()方法
      1)静态方法:static void yield()
      2)作用:让位方法,当前线程暂停,回到就绪状态
      3)与sleep区别:跳过阻塞直接进入就绪状态
      yield()只是使当前线程重新回到可执行状态,
      所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

      4、关于线程的join()方法
      1)实例方法:void join()
      2)作用:加入一个线程并合并,但让当前线程受阻塞,直到加入的线程结束
      无参阻塞时间为:加入的线程结束
      一个参数代表:阻塞该线程的时间最长为millis毫秒
      两个参数代表:阻塞该线程的时间最长为millis毫秒加nanos纳秒

      5、关于线程通信
      1.线程通信涉及到的三个方法:
        * wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
        * notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
        * notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
      2.说明:
        * 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
        * 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。
        *    否则,会出现IllegalMonitorStateException异常
        * 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。
        * 4.notify()调用后,并不是马上就释放对象锁的,
        *  而是在相应的synchronized(){}语句块执行结束,自动释放锁后,
        *  JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。







     新增方式一:实现Callable接口。 --- JDK 5.0新增
     需要先使用FutureTask构造器传参
     说明:
* 如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?
* 1. call()可以返回值的。
* 2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
* 3. Callable是支持泛型的

      新增方式二:使用线程池
      好处:
* 1.提高响应速度(减少了创建新线程的时间)
* 2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)
* 3.便于线程管理
*      corePoolSize:核心池的大小
*      maximumPoolSize:最大线程数
*      keepAliveTime:线程没任务时最多保持多长时间后会终止
 */
public class ThreadAndRunnable {
    public static void main(String[] args) throws InterruptedException {
        Thread01 testThread=new Thread01();
        testThread.start();
        testThread.setName("Thread:");
        try {
            testThread.sleep(10);//这段代码不会让testThread线程进入休眠
        } catch (InterruptedException e) {//这行代码的作用是:让当前线程进入休眠状态,也就是main进程
            throw new RuntimeException(e);//这行代码出现在main方法中,会让mian线程休眠
        }                                 //此外主线程休眠就不能进行下面的代码,所以这时testRunnable线程还没启动

        testThread.interrupt();//中断th线程的睡眠(这种中断睡眠的方式依靠了Java的异常处理机制)

//结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,
// 但有可能没有效果。
        Runnable01 T=new Runnable01();
        Thread testRunnabla=new Thread(new Runnable01());
        testRunnabla.start();
        testRunnabla.setName("Runnable");
        testRunnabla.setPriority(10);




      Thread.currentThread().setPriority(1);
        for (int i=0;i<=100;i++){
            yield();//让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会
            System.out.println("主线程");

        }


        FutureTask task=new FutureTask(new TestCallable() );
        Thread task00=new Thread(task);
        task00.start();
        System.out.println(Thread.currentThread().getName());






    }
}
class Thread01 extends Thread
{
    @Override
    public void run() {
        for (int i=0;i<=100;i++)
        {
            System.out.println(Thread.currentThread().getName()+":"+i);



        }
        try {
            sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        finally {
            System.out.println("结束销毁");
        }
    }
}
class Runnable01 implements Runnable
{

    @Override
    public void run() {
        for (int i=0;i<=100;i++)
            System.out.println(Thread.currentThread().getName()+":"+i);
    }
}
class TestCallable implements Callable
{
    @Override
    public Object call() throws Exception {
        System.out.println("方式三");
        return null;
    }
}
import static java.lang.Thread.sleep;

public class ThreadSynchronized
/*
            5、关于线程通信
      1.线程通信涉及到的三个方法:
        * wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
        * notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
        * notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
      2.说明:
        * 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
        * 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。
        *    否则,会出现IllegalMonitorStateException异常
        * 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。
        * 4.notify()调用后,并不是马上就释放对象锁的,
        *  而是在相应的synchronized(){}语句块执行结束,自动释放锁后,
        *  JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。

             6、线程同步
        1.synchronized关键字
              1.1同步代码块

        语法:synchronized(同步监视器/锁/对象)
        {
            //线程同步代码块
        }
        重点:
        synchronized后面小括号() 中传的这个“数据”是相当关键的。这个数据必须是 多线程共享 的数据。才能达到多线程排队。

        说明:   1.操作共享数据的代码,即为需要被同步的代码。  -->不能包含代码多了,也不能包含代码少了。
        *       2.共享数据:多个线程共同操作的变量。
        *       3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
        *          要求:多个线程必须要共用同一把锁。
        *
        * 补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。
               在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。

              1.2同步方法
        *     如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
        *  关于同步方法的总结:
        *  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
        *  2. 非静态的同步方法,同步监视器是:this
        *     静态的同步方法,同步监视器是:当前类本身
        (如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,
        其它线程不能同时访问这个对象中任何一个synchronized方法)

               1.3Lock锁  --- JDK5.0新增
        * 1. 面试题:synchronized 与 Lock的异同?
        *   相同:二者都可以解决线程安全问题
        *   不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器
        *        Lock需要手动的启动同步(lock(),同时结束同步也需要手动的实现(unlock())

        使用的优先顺序:
        * Lock ---> 同步代码块(已经进入了方法体,分配了相应资源 ) ---> 同步方法(在方法体之外)
        3.利弊
        同步的方式,解决了线程的安全问题。---好处
        操作同步代码时,只能一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。


             7、多线程并发下的数据安全问题
    1.条件:1.1:多线程并发
           1.2:存在共享数据
           1.3:共享数据有修改的行为
    2.说明:2.1在多线程下有可能存在多个线程同时修改共享数据,导致数据异常
           2.2这是就不能让线程异步(并发)引出线程同步(排队)
           2.3缺点:效率降低

              8、java中有三大变量
    1.实例变量:在堆中
    2.静态变量:在方法区中
    3.局部变量:在栈中

  *PS:4.1以上三大变量,局部变量是没有线程安全问题的,因为数据不共享啊
         一个线程一个栈,局部变量在栈中
      (另外常量也没有线程问题虽然在常量池共享,但是不能被改变)
      4.2堆与方法区都是多线程共享的,蓑衣存在线程问题(堆与方法区只有一个)


               9、开发中线程安全问题的解决
         1.第一种方案:尽量使用局部变量代替实例变量与静态变量
         2.第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,一个对象对应一个线程
                      让线程对象不共享,就没有共享数据了
         3.第三种方案:不能使用局部变量,也不能创建多个对象,这时只能使用synchronized同步线程


                10、死锁
                Java死锁是指两个或多个线程在互相等待对方释放资源,导致所有线程都无法继续执行的状态。
                常见的解决方法是:避免循环等待、避免拥有锁的线程在等待资源时被阻塞、增加重试机制等。

                11、守护线程
         1.java语言中线程分为两大类
                :用户线程(main法方主线程)
                :守护线程(代表垃圾回收线程)
         2.守护线程的特点:
            一般都是一个死循环,随着用户线程共存,用户线程消亡,守护也消亡
         3.方法
         :void setDaemon(boolean on )
         (on 表示把线程设置为守护线程)

                *、关于合理结束一个进程的执行(常用)
      1..stop()方法(已经过时)
      因为这种方式直接将线程杀死,线程没有保存,容易丢失数据
      2.,线程正常执行完毕,正常结束。
        也就是让run方法执行完毕,该线程就会正常结束。
      3..
 */
{
    public static void main(String[] args) throws InterruptedException {
        TestSynchronized02 a = new TestSynchronized02();
        TestSynchronized02 b = new TestSynchronized02();
        TestSynchronized02 c = new TestSynchronized02();

        TestSynchronized01 A=new TestSynchronized01("A",c,a);
        TestSynchronized01 B=new TestSynchronized01("B",a,b);
        TestSynchronized01 C=new TestSynchronized01("C",b,c);
       Thread AAA= new Thread(A);
        AAA.start();
        sleep(100);
        Thread BBB=new Thread(B);
        BBB.setDaemon(true);
        BBB.start();
        sleep(100);
        Thread CCC=new Thread(C);
        CCC.setDaemon(true);
        CCC.start();
        sleep(100);

        System.out.println(AAA.isAlive());
       // BBB.interrupt();//z中断不代表死亡
       // CCC.interrupt();


        System.out.println(BBB.isAlive());
        System.out.println(CCC.isAlive());
        System.out.println(Thread.currentThread().getName());









//        A.t2();
//        B.t2();
//Deadlock00 O=new Deadlock00();
//Deadlock11 X=new Deadlock11();


//new TestDeadLock00(O,X).start();
            //打开是死锁
//new Thread(new TestDeadLockxx(O,X)).start();
    }
}
class TestSynchronized01 implements Runnable
{
    private String name;
    private  Object prev;
    private Object self;
    TestSynchronized01(String name,Object prev,Object self)
    {
        this.name=name;
        this.prev=prev;
        this.self=self;
    }

    @Override
    public void run() {
        int count=10;
        while(count>0) {
            synchronized (prev) {
                synchronized (self) {
                    System.out.println(Thread.currentThread().getName()+this.name);
                    count--;
                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }


            }
        }
//                synchronized (this)
//                {
//                    notifyAll();
//                    System.out.println(Thread.currentThread().getName());
//                }


    }
    public synchronized void t1() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"01");
        sleep(10000);
    }
    public synchronized void t2()
    {
        System.out.println(Thread.currentThread().getName()+"02");
    }
}
class TestSynchronized02 extends Thread
{


    @Override
    public void run() {
        System.out.println("02");
    }
}


class Deadlock00
{

}
class Deadlock11
{

}
class TestDeadLock00 extends Thread
{
    Deadlock00 oo;
    Deadlock11 xx;
    public TestDeadLock00(Deadlock00 oo, Deadlock11 xx)
    {
        this.oo=oo;
        this.xx=xx;
    }
    @Override
    public void run() {
        synchronized(oo) {
            System.out.println(Thread.currentThread().getName());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (xx) {
                System.out.println(Thread.currentThread().getName());
            }
        }
    }
}
class TestDeadLockxx implements Runnable
{   Deadlock00 oo;
    Deadlock11 xx;

    public TestDeadLockxx(Deadlock00 oo,Deadlock11 xx) {
        this.oo=oo;
        this.xx=xx;
    }

    @Override
    public void run() {
        synchronized(xx) {
            System.out.println(Thread.currentThread().getName());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (oo) {
                System.out.println(Thread.currentThread().getName());
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值