美文网首页
Java基础5

Java基础5

作者: Jy_北海 | 来源:发表于2018-04-17 22:47 被阅读0次

    Java多线程:

    进程:进行中的程序

    线程:就是进程中一个负责程序执行的控制单元(执行单元)

    一个进程中可以多执行路径,称之为多线程

    一个进程至少一个线程

    开启多个线程是为了同时运行多部分代码

    每个线程都有自己运行的内容,这个内容成为线程要执行的任务

    多线程的好处:解决了多部分同时运行的问题

    多线程的弊端:线程太多回到效率的降低

    其实应用程序的执行都是CPU在做着快速的切换完成的,这个切换是随机的

    JVM启动时就启动了多个线程,至少有两个线程

    1.执行main函数的线程

    该线程的任务代码都定义在main函数里

    2.负责垃圾回收的线程

        如何创建一个线程:

        方式一:继承Thread类

        步骤:

        1.创建一个类继承Thread类

        2.重写Thread的run方法//重写run方法

        3.直接创建Thread类的子类对象C创建线程

        4.调用start方法开启线程并调用线程的任务run方法执行

        class Demo extends Thread

    {

    private String name = "弟鸽";

    Demo(String name)

    {

    super(name);

    //this.name = name;

    }

    public void run(){

    for(int i=1;i<10;i++)

    {

    for(long j= -199999999;j<199999999;j++){ }

    system.out.println(name+"*****"+i+"--------"

    +Thread.currentThread().getName());

    }

    }

    }

    main(){

    Demo d1 = new Demo("脔割");

    Demo d2 = new Demo("儿纸");

    //d1.run();

    //d2.run();

    d1.start();

    d2.start();

    }

        可以通过Thread的getName获取线程的名称 Thread—(0开始)

        主线程的名称是 main

        创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码同时运行

        而运行的指定代码就是这个执行路径的任务

        JV创建的主线程的任务都定义在主函数里

        自定义的线程的任务在run方法里;

        Thread类用于描述线程,线程是 需要任务的,所以Thread类也对任务的描述,这个任务就通过Thread类中的run方法实现。也就是说,run方法就是封装自定义线程运行任务的函数。

        run方法中定义的就是线程要运行的任务代码

        开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法,将要运行的代码定义在run方法中即可。

        run()和start()的区别:

        1.start()可以启动一个新的线程

        2.start()不能重复调用run()可以

        3.start()中的run()代码可以不执行完就继续执行下面的代码,即进行了线程切换。直接调用run()方法必须等待其代码全部执行完才能继续执行下面的代码

        4.start()实现了多线程,run()没有实现多线程

        临时阻塞状态 具备执行资格但不具备执行权 正在等待执行权

        ↑   ↑

        ↓                      ↑

        进程--->start()--->运行--->sleep(time)--->冻结//释放执行权的同时

        | --->  wait()  --->↑   释放执行资格

        ↓ <---  notify() <---↑

          stop()

          |

          ↓

          消亡

      cpu执行资格: 可以被cpu处理,在处理队列中排队

      cpu的执行权: 正在被cpu处理

      创建线程的第二种方法:

      1.定义类实现Runnable接口

      2.覆盖接口种的run方法,将线程的任务代码封装到run方法中

      3.通过Tread类创建对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。(原因是线程任务都封装在Runnable接口子类对象的run方法中,所以在线程对象创建时就得明确要运行的任务。)

      4.调用线程对象的start方法开启线程

      class Demo2 implements Runnable //准备扩展Demo2类的功能,让其中的内容作为线程的任务执行

      //通过接口的形式完成

    {

    public void run()

    {

    show();

    }

    public void show(){

    for(int i=1;i<10;i++)

    {

    for(long j= -199999999;j<199999999;j++){}

    System.out.println(Thread.currentThread().getName());

    }

    }

    }

    main()

    {

    Demo2 d3 = new Demo2();

    Thread t1 = new Thread(d3,"办证");

    Thread t2 = new Thread(d3,"学妹介绍Q");

    t1.start();

    t2.start();

    }

    Runnable接口:将线程的任务进行了对象的封装

    实现Runnable接口的好处:

    1.将线程的任务从线程的子类中分离出来,进行了单独的封装

    按照面向对象的思想将任务的封装成对象

    2.避免了Java单继承的局限性

    故较为常用的是实现Runnable

    线程安全问题产生的原因:

    1.多个线程在操作共享的数据

    2.操作共享数据的代码有多条

    当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算

    就会导致线程安全问题的产生

    解决思路:

    就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,必须要当成线程把这些代码都执行完毕后,其他线程才可以  ------->局部代码块

    在Java中用同步代码块就可以解决这个问题

    synchronized(对象)

    {

    局部代码;

    }

    同步的好处:

    解决了线程的安全问题

    同步的弊端:

    相对降低了效率,因为同步外的线程都会判断同步锁。

    同步的前提:

    同步中必须有多个线程吗,并使用同一个锁。

    同步函数的锁是this

    同步函数和同步代码块的区别:

    1.同步函数的锁是固定的this

    同步代码块的锁是任意的对象

    建议使用同步代码块

    当同步函数为static时,锁为this.getClass()即该函数所属字节码文件对象,可用getClass()方法获取,也可以用当前

    类名.class 表示。

    死锁:

    class DeadLockTestDemo implements Runnable

    {

    private boolean flag;

    DeadLockTestDemo(boolean flag)

    {

    this.flag = flag;

    }

    public void run()

    {

    if(flag)

    {

    while(true)

    synchronized(MyLock.lockA)

    {

    System.out.println(Thread.currentThread().getName()+"--If--->LockA");

    synchronized(MyLock.lockB)

    {

    System.out.println(Thread.currentThread().getName()+"--If--->LockB");

    }

    }

    }

    else

    {

    while(true)

    synchronized(MyLock.lockB)

    {

    System.out.println(Thread.currentThread().getName()+"--Else--->LockB");

    synchronized(MyLock.lockA)

    {

    System.out.println(Thread.currentThread().getName()+"--Else--->LockA");

    }

    }

    }

    }

    }

    class MyLock

    {

    public static final Object lockA = new Object();

    public static final Object lockB = new Object();

    }

    public class DeakLockTest {

    public static void main(String[] args) {

    DeadLockTestDemo dlt1 = new DeadLockTestDemo(true);

    DeadLockTestDemo dlt2 = new DeadLockTestDemo(false);

    Thread t1 = new Thread(dlt1);

    Thread t2 = new Thread(dlt2);

    t1.start();

    t2.start();

    }

    }

    进程间的通信:

    等待/唤醒机制

    1.wait(): 让cpu处于冻结状态,被wait的线程会被存储到线程池中

    2.notify(): 唤醒线程池中的一个线程(任意)

    3.botifyAll():唤醒线程池中的所有线程

    class Resource

    {

    String name;

    int age;

    boolean flag = false;

    }

    class Input implements Runnable

    {

    Resource r;

    Input(Resource r)

    {

    this.r = r;

    }

    public void run()

    {

    int x = 0;

    while(true)

    {

    synchronized(r)

    {

    if(r.flag)

    try {

    r.wait();

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    if(x==0)

    {

    r.name = "脔割";

    r.age = 18;

    }

    else

    {

    r.name = "弟鸽";

    r.age = 17;

    }

    r.flag = true;

    r.notify();

    }

    x = (x+1)%2;

    }

    }

    }

    class Output implements Runnable

    {

    Resource r = new Resource();

    Output(Resource r)

    {

    this.r = r;

    }

    public void run()

    {

    while(true)

    synchronized(r)

    {

    if(!r.flag)

    try {

    r.wait();

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    System.out.println(r.name+"--->"+r.age);

    r.flag = false;

    r.notify();

    }

    }

    }

    public class ResourceDemo {

    public static void main(String[] args) {

    Resource r = new Resource();

    Input in = new Input(r);

    Output out = new Output(r);

    Thread t1 = new Thread(in);

    Thread t2 = new Thread(out);

    t1.start();

    t2.start();

    }

    }

    线程的wait();notify();notifuAll()定义在Oblect类中的原因是:

    因为这些方法是监视器的方法,监视器其实就是锁。

    锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中

    相关文章

      网友评论

          本文标题:Java基础5

          本文链接:https://www.haomeiwen.com/subject/znkmkftx.html