线程
线程概念
程序- 进程 - 线程
1.程序
1.是为了完成特定的任务,用某一种语言来进行编写的一组指令的集合
2.进程
1.是程序的一次执行,或者是在正在运行的一个程序,是系统运行程序的一个基本的单位
2.每个进程都有一个独立的内存空间,一个应用程序可以同时进行运行多个进程
3.系统运行的一个程序即是一个进程的创建,运行到消亡的一个过程
3.线程
1.进程可以在一步的细化,叫做线程(一个执行的单元)
2.负责当前进程中的程序的运行,一个进程中至少有一个线程,当然可以是多个线程
3.如一个程序可以同时执行多个线程,那么就支持多线程的
4.注意:
java有个一个主函数,请问主函数里面至少有几条线程
至少是两条
4.多线程使用的场景
1.如百度网盘,下载数据,同时下载多个
2.微信多人开视频
5.多线程的并行和并发之间的区别
1.并行
就是两个线程同时运行,如A线程任务进行的同时,B线程任务也在进行
那么需要多核CPU
2.并发
是指两个任务都是请求运行,(在同一时间进行发生) ,而处理只能进行处理一个任务,就把两个任务安排进行轮流执行
证明:
java有个一个主函数,请问主函数里面至少有几条线程
注意:
Jvm 启动的时候,至少进行启动了两条线程,
垃圾回收机制和主线程
@Test
public void getVoid01(){
for (int i = 0; i < 10; i++) {
new Filalise();
}
for (int i = 0; i < 10; i++) {
System.out.println("我是主线程");
System.gc();//跟催
}
}
}
class Filalise{
@Override
protected void finalize() throws Throwable {
System.out.println("我执行了------清除机制");
}
}


线程的启动-创建方式
方式一 使用类
public class Test_Thred_01 {
/*
测试执行线程
*/
@Test
public void getVoid01(){
/
在线程中不能这样的操作
MYyThred mYyThred = new MYyThred();
mYyThred.run();*/
MYyThred mYyThred = new MYyThred(); //创建线程的实例对象
//进行开启线程
mYyThred.start();
}
}

    //当前类就拥有的线程
    class MYyThred extends  Thread{
         //必须要进行实现对应的run方法
        @Override
        public void run() { //就是来进行执行线程的业务逻辑的
            for (int i = 0; i < 10; i++) {
                System.out.println("我执行了线程:" + i + ":次");
            }
        }
    }

方式二 使用接口
public class Test_Runable_03 {

     /**
      测试线程
     */
      @Test
     public   void  getVoid(){
            //开启线程
          MyRunbale myRunbale = new MyRunbale(); //创建Runnable实现类的实现化对象
          Thread thread = new Thread(myRunbale);  //将其如上的实例化的对象,当成参数传递给Thread
          thread.start();//开启线程
      }
}


class  MyRunbale implements  Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我执行了线程:" + i + "次数");
        }
    }
}

注意:
1.run方法是多线程的一个执行的目标,不直接使用对象名来进行调用
所有的线程中的执行的业务逻辑都是在run方法中执行的
2.如要进行执行run方法,必须通过start方法来进行开启
而start方法是在Thread中才会进行调用的如使用接口的方式来进行创建线程
需要将该接口的实现类实例化的对象传入到Thread对象中,


Thread 与 Runnable (频率高)之间的区别
1.如使用继承的方式,Thread ;则是不适合资源的共享(因为java类中不能多继承,只能当前类拥有该线程)
2.如使用了实现类的方式Runnable,可以实现资源共享,(因为接口可以多实现,只要多个类实现了该接口这都拥有了该线程的资源)
3.使用了Thread 类必须要进行重写Run方法,在使用start方法来进行开启线程,JVM会帮助我们查找Run并执行
4.使用接口,则必须要当成参数传递到Thread 对象中


内部类的创建线程
继承
/**
实现内部类的方式来进行创建
*/
@Test
public void getVoid(){
new Thread(){
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("我执行了,内部类的线程" + i + "次数");
}
}
}.start();
}

        @Test
        public   void  getVoid02(){
          Thread  th=  new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 30; i++) {
                        System.out.println("我执行了,内部类的线程" + i + "次数");
                    }
                }
            };
            th.start();
        }

实现
/**
使用内部类的来进行实现
*/
@Test
public void getVoid01(){

                 new Thread(new Runnable() {
                         @Override
                         public void run() {
                             for (int i = 0; i < 20; i++) {
                                 System.out.println("我执行了" + i);
                             }
                         }
                 }).start();

           }
        @Test
        public   void  getVoid02(){

        Thread th=    new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 20; i++) {
                        System.out.println("我执行了" + i);
                    }
                }
            });
            th.start();

        }

----常用的方法---------------------------
void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回
getName()
返回该线程的名称。
setName(String name)
改变线程名称,使之与参数 name 相同。
@Test
public void getVoid01(){
MYyThred_Method mYyThred_method = new MYyThred_Method();
mYyThred_method.start();
mYyThred_method.setName("我的线程--");

             System.out.println(mYyThred_method.getName());
             System.out.println("----------");
             MYyThred_Method mYyThred_method01 = new MYyThred_Method();
             mYyThred_method01.start();
             mYyThred_method01.setName("你的线程");
             System.out.println(mYyThred_method01.getName());

         }

static Thread currentThread()
返回对当前正在执行的线程对象的引用。
@Test
public void getVoid02(){
MYyThred_Method mYyThred_method = new MYyThred_Method();
mYyThred_method.start();
mYyThred_method.setName("我的线程--");
System.out.println("----------");

            Thread.currentThread().setName("我是主线");
            System.out.println(Thread.currentThread().getName());
        }

static void sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
static void sleep(long millis, int nanos)
在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响
public static void main(String[] args) {
/*
Thread thread= new Thread(){
//@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我执行了方法" + i);
}
}
};thread.start();*/

          new Thread(new Runnable(){
             //@Override
             public void run() {
                 for (int i = 0; i < 10; i++) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println("我执行了方法" + i);
                 }
             }
         }).start();
     }

void setDaemon(boolean on) 守护线程 将该线程标记为守护线程或用户线程。
1.该线程不会单独的执行,当其他的线程(非守护线程)都执行结束后,自动会退出
public static void main(String[] args) {

        Thread   TH01=    new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("我执行了方法" + i);
                }
            }
        });

        TH01.start();

        Thread   TH02=    new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("z执行了-----你的方法" + i);
                }
            }
        });
        TH02.setDaemon(true);//设置为守护线程
        TH02.start();
    }

       void join()
                等待该线程终止。
       void join(long millis)
                等待该线程终止的时间最长为 millis 毫秒。
       void join(long millis, int nanos)
                等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
1.当某个程序执行中,调用其他的线程的join方法,调用线程将被阻塞,等待指定的join线程执行完为止
  当前的线程在继续
2.可以进行设置多少秒之后,在进行执行
           public static void main(String[] args) {

                Thread   TH=    new Thread(new Runnable(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 100; i++) {
                            System.out.println("==================我执行了方法" + i);
                        }
                    }
                });



                Thread   TH02=    new Thread(new Runnable(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 100; i++) {
                            if (i==10) {
                                try {
                                    TH.join();//插队,可以进行指定时间,过了指定的时间后,两条线程交替执行
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            System.out.println("z执行了-----你的方法" + i);
                        }
                    }
                });


                TH.start();
                TH02.start();
            }

static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
1.在线程执行的过程中让出CUP
public class Test_Method_07 {

    public static void main(String[] args) {
    //    MyIsThreod myIsThreod = new MyIsThreod();
        new MyIsThreod().start();
        new MyIsThreod().start();

    }

}

class MyIsThreod extends Thread{

@Override
public void run() {
    for (int i = 0; i < 20; i++) {
        if (i%5==0) {
            Thread.yield();
            System.out.println("-------------------我礼让了" + getName() + ":" + i);
        }
        System.out.println("我执行了"+getName()+"::"+ i);
    }
}

}

线程的_同步
1.多个同步的代码块如果使用了相同的锁对象,那么他们就同步的
2.使用synchronized 关键字 加上,表示是一个锁,该代码块就是叫做同步代码块
什么环境下需要使用同步
1.多线程的并发,有多个代码片段同时执行的时候,
我们需要某一个段代码片段在执行的过程中,CPU不要进行切换到其他的线程工作
这个时候就是需要同步
2.如果多个代码片段都是同步的,那么同一时间只能执行一段,在一段代码没执行结束之前,其他代码片段是不会执行

/**
 * 没有进行同步的情况
 */
public void getMethod01(){
    System.out.print("getMethod01,执");
    System.out.print("行");
    System.out.print("了");
    System.out.print("方");
    System.out.print("法");
    System.out.print("\r\n");
}

public void getMethod02(){
    System.out.print("getMethod02,执");
    System.out.print("行");
    System.out.print("了");
    System.out.print("方");
    System.out.print("法");
    System.out.print("\r\n");
}

public static void main(String[] args) {
    Test_Synchronized_08 test_synchronized_08 = new Test_Synchronized_08();

    new  Thread(){
        @Override
        public void run() {
            while (true) {
                test_synchronized_08.getMethod01();
            }
        }
    }.start();
    new  Thread(){
        @Override
        public void run() {
            while (true) {
                test_synchronized_08.getMethod02();
            }
        }
    }.start();
}
/**
同步的情况下
    /**
     * 没有进行同步的情况
     */
    public void getMethod01(){
        synchronized (this){
        System.out.print("getMethod01,执");
        System.out.print("行");
        System.out.print("了");
        System.out.print("方");
        System.out.print("法");
        System.out.print("\r\n");
        }
    }

    public void getMethod02(){
        synchronized (this){
        System.out.print("getMethod02,执");
        System.out.print("行");
        System.out.print("了");
        System.out.print("方");
        System.out.print("法");
        System.out.print("\r\n");
    }
    }

    public static void main(String[] args) {
        Test_Synchronized_09 test_synchronized_08 = new Test_Synchronized_09();

        new  Thread(){
            @Override
            public void run() {
                while (true) {
                    test_synchronized_08.getMethod01();
                }
            }
        }.start();
        new  Thread(){
            @Override
            public void run() {
                while (true) {
                    test_synchronized_08.getMethod02();
                }
            }
        }.start();
    }
}

注意:
1.在任何的情况下,最多允许一个线程有同步锁,谁获取到这个锁,谁就进入该代码块
2.其他的线程只能在外面等待
同步锁是谁
对于非static 方法,同步锁就是this
this 是创建对象之后产生的,静态方法和优先于对象的
对静态方法,我们使用当前方法所在类的字节码对象名称
静态方法的锁对象是本类的Class属性(类名.class)反射
也是可以在方法加上锁的
public class Test_Synchronized_10 {

    /**
     * 没有进行同步的情况
     */
    public synchronized void getMethod01(){
            System.out.print("getMethod01,执");
            System.out.print("行");
            System.out.print("了");
            System.out.print("方");
            System.out.print("法");
            System.out.print("\r\n");
    }

    public synchronized void getMethod02(){
        System.out.print("getMethod02,执");
        System.out.print("行");
        System.out.print("了");
        System.out.print("方");
        System.out.print("法");
        System.out.print("\r\n");
    }

    public static void main(String[] args) {
        Test_Synchronized_10 test_synchronized_08 = new Test_Synchronized_10();

        new  Thread(){
            @Override
            public void run() {
                while (true) {
                    test_synchronized_08.getMethod01();
                }
            }
        }.start();
        new  Thread(){
            @Override
            public void run() {
                while (true) {
                    test_synchronized_08.getMethod02();
                }
            }
        }.start();
    }
}

==================================================

线程的生明周期
1.当线程被创建并进行启动以后,它不是一个启动就要进入执行的状态,也不是处于执行的状态
2.java语言中使用线程类以及子类的对象来进行表是线程,它的完整的生明周期有以下的6种

new 新建
线程被创建,但是并未开启
还没有进行调用start方法
如:class MyIsThreod extends Thread;
MyIsThreod my= new MyIsThreod()
Runnable 可运行
线程可以在java虚拟机中运行的状态
可能正在运行自己的代码,也可能没有,取决于操作系统的处理器
Blocked 锁阻塞
当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有
则该线程进入了锁阻塞状态
当该线程持有锁的时候,该线程就变成了Runnable 可运行状态
Waiting 无限的等待
一个线程在等待另外一个线程执行一个(唤醒)的动作。那么该线程就是进入了 Waiting 无限的等待的状态
进入了这个状态的时候,是不能自动的唤醒的,必须要进行等待另外一个线程来进行调用notify 或者 notityAll 方法才能进行唤醒
TimeWaiting 计时的等待
同(Waiting 无限的等待)类似,有几个方法有设置时间的参数,如Sleep...来进行调用这些方法进入一个TimeWaiting 计时的等待状态
这个状态如超过了这个设置的时间就会进行执行唤醒的操作

Teminated 被终止
因为run方法,正常退出而进行死亡,或者是因为没有捕获的异常而导致run方法死亡


线程安全问题
1.多线程并发,操作作为同一数据的时候,那就有可能出现线程安全问题
2. 使用同步的技术,可以来进程处理个问题,把操作数据的代码进行同步,加上对应的锁
实现购票案例
方式一
public class Test_Synachronized_12 {

            public static void main(String[] args) {
                MyThisIsThread myThisIsThread = new MyThisIsThread();
                MyThisIsThread myThisIsThread01 = new MyThisIsThread();
                MyThisIsThread myThisIsThread02 = new MyThisIsThread();
                MyThisIsThread myThisIsThread03 = new MyThisIsThread();
                myThisIsThread.setName("窗口1");
                myThisIsThread01.setName("窗口2");
                myThisIsThread02.setName("窗口3");
                myThisIsThread03.setName("窗口4");

                myThisIsThread.start();
                myThisIsThread01.start();
                myThisIsThread02.start();
                myThisIsThread03.start();
            }

        }

        class MyThisIsThread extends  Thread{
              //票的总数
             private  static   int  number=100;

             //创建一个锁对象
           private  static Object  object=new Object();

            public MyThisIsThread() {
                super();
            }

            public MyThisIsThread(String name) {
                super(name);
            }

            @Override
            public void run() {

                while (true) {
                   // synchronized (object){
                    synchronized (MyThisIsThread.class){
                    if (number<=0)
                            break;
                            try {
                                Thread.sleep(1000);

                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                                System.out.println(getName() + "获取到了第" + number-- + "号票");
                }
                }

            }
        }
     方式二:


public static void main(String[] args) {
    MyThisIsThread myThisIsThread = new MyThisIsThread();
    MyThisIsThread myThisIsThread01 = new MyThisIsThread();
    MyThisIsThread myThisIsThread02 = new MyThisIsThread();
    MyThisIsThread myThisIsThread03 = new MyThisIsThread();
    myThisIsThread.setName("窗口1");
    myThisIsThread01.setName("窗口2");
    myThisIsThread02.setName("窗口3");
    myThisIsThread03.setName("窗口4");

    myThisIsThread.start();
    myThisIsThread01.start();
    myThisIsThread02.start();
    myThisIsThread03.start();
}

}

class MyThisIsThread extends Thread{
//票的总数
private static int number=100;

 //创建一个锁对象

private Object object=new Object();

public MyThisIsThread() {
    super();
}

public MyThisIsThread(String name) {
    super(name);
}

@Override
public void run() {

    while (true) {
      synchronized (object){ //4个窗口  3个

                        synchronized (MyThisIsThread.class){//支持一个
                        if (number<=0)
                                break;
                                try {
                                    Thread.sleep(1000);

                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                    System.out.println(getName() + "获取到了第" + number-- + "号票");
                   }
      }

    }

}

}

死锁
在工作中是禁止出现的
1.在多线程中同步的时候,如果同步的代码块发送故障,就会出现对应的死锁
2.两个线程都是同步的,但是线程A获取到了线程B的锁对象,线程B获取到了线程A的锁对象,他们都是进行等待着对方释放锁对象
死锁

private   static  String  s1="左筷子";
private   static  String  s2="右筷子";

public static void main(String[] args) {
       new Thread(){
           @Override
           public void run() {
               while (true) {
                    synchronized (s1){
                        System.out.println(getName() + "获取到了" + s1 + "等待" + s2);
                        synchronized (s2){
                            System.out.println(getName() + "获取到了"  + s2+"开始吃包子");
                        }
                    }
               }
           }
       }.start();


    new Thread(){
        @Override
        public void run() {
            while (true) {
                synchronized (s2){
                    System.out.println(getName() + "获取到了" + s2 + "等待" + s1);
                    synchronized (s1){
                        System.out.println(getName() + "获取到了"  + s1+"开始吃包子");
                    }
                }
            }
        }
    }.start();


}

}