java高级编程——多线程

一、最常见的创建线程的两种方式

1.继承Thread

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/26.
 */
public class MyThread1 extends Thread {

    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        MyThread1 t2 = new MyThread1();

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

【详解】继承Thread类,重写父类的run()方法,然后执行一系列操作。程序首先从mai()方法进入,然后通过new  MyThread1()创建了两个对象,调用setName()可以修改线程名,调用start()方法可以让线程被开启。run()方法会被回调,其中currentThread()是静态方法,sleep()方法也是Thread的静态方法,代码里的sleep()其实就是this.sleep(),而this就是该方法被调用的对象,很显然是Thread.sleep();

2、实现Runnable接口

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/26.
 */
public class MyThread2 implements Runnable {

    public static void main(String[] args) {
        MyThread2 t1 = new MyThread2();
        MyThread2 t2 = new MyThread2();

        Thread thread1=new Thread(t1);
        Thread thread2=new Thread(t2);

        thread1.setName("线程1");
        thread2.setName("线程2");

        thread1.start();
        thread2.start();
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

【详解】第二种方式是通过实现Runnable接口,重写run()方法,而我们还是需要newThread(),调用start()方法开启线程。这里的sleep()前面需要加Thread,因为此时的run()是new Thread()这个对象调用的,this指向的是new Thread()这个对象

【运行结果】

二、线程的生命周期

创建了线程之后,调用start()方法,线程进入就绪状态,只有当线程获得了CPU,就会到达运行状态,此时run()方法就会被执行,可能还没执行完,失去了CPU,就会回到就绪状态,等待下次获取到CPU之后继续执行run()方法。这就是为什么上述例子两个子线程交互执行for循环。通过调用sleep()方法可以让线程进入阻塞状态,等待时间到后又回到就绪状态。

三、给线程加锁

简单介绍java的内存分配,jvm内存主要包括

栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。

 堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

方法区:包含如下内容:

 常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于方法区中。

代码段:用来存放从硬盘上读取的源程序代码。

数据段:用来存放static定义的静态成员。

》》其中每个线程都会有一个属于自己的栈,而堆、方法区都是所有线程共享的,这就存在数据同步的问题。比如在售票的时候,多个窗口去共享同一个数据,这个时候就会出现重票或负票的情况。线程在共享数据方面通过加锁来实现线程同步,就比如很多人排队上厕所,然后一个一个的进去,进去一个锁一下门,等他出来后把锁交给另一个人。

实现线程同步的方法有两种:

1.同步代码块

2.同步方法

1.实现Runnable的同步代码块

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/24.
 */
public class ThreadTest implements Runnable{
/**
 * 线程同步:
 * 1.同步代码块synchronized(同步监视器:锁){
 *     //需要同步的代码
 * }
 * 2.同步方法
 *
 */

//任何对象都能充当锁
Object obj=new Object();
public  int ticket=100;
    @Override
    public void run() {
        while (true){
            synchronized (obj) {//synchronized (this) {
                if(ticket>0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖出第" + ticket + "张票");
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadTest t1=new ThreadTest();
        new Thread(t1).start();
        new Thread(t1).start();
        new Thread(t1).start();
    }
}

2.实现Runnable的同步代码块

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/24.
 */
public class ThreadTest2 implements Runnable{
/**
 * 线程同步:
 * 1.同步代码块synchronized(同步监视器:锁){
 *     //需要同步的代码
 * }
 * 2.同步方法
 *
 */

public  int ticket=100;
    @Override
    public void run() {
        while (true){
            Boolean b=reduce();
              if(b){
                  break;
              }
        }
    }

    public synchronized Boolean reduce(){
        if(ticket>0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖出第" + ticket + "张票");
            ticket--;
        }else {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        ThreadTest2 t1=new ThreadTest2();
        new Thread(t1).start();
        new Thread(t1).start();
        new Thread(t1).start();
    }
}

3.继承Thread的同步代码块

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/24.
 */
public class ThreadTest3 extends Thread {

    public static int ticket = 100;

    public static void main(String[] args) {
        ThreadTest3 t1 = new ThreadTest3();
        ThreadTest3 t2 = new ThreadTest3();
        ThreadTest3 t3 = new ThreadTest3();
        t1.start();
        t2.start();
        t3.start();

    }

    @Override
    public void run() {
        while (true) {
            synchronized (ThreadTest3.class) {//synchronized (obj) {
                if (ticket > 0) {
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖出第" + ticket + "张票");
                    ticket--;
                } else {
                    break;
                }
            }

        }
    }
}

4.继承Thread的同步代码块

package com.xioayu.threadTest1;

/**
 * Created by hasee on 2019/5/24.
 */
public class ThreadTest4 extends Thread {

    public static int ticket = 100;

    public static void main(String[] args) {
        ThreadTest4 t1 = new ThreadTest4();
        ThreadTest4 t2 = new ThreadTest4();
        ThreadTest4 t3 = new ThreadTest4();
        t1.start();
        t2.start();
        t3.start();

    }

    @Override
    public void run() {
        while (true) {
            Boolean b=ThreadTest4.reduce();
            if(b){
                break;
            }

        }
    }

    public static synchronized boolean reduce() {
        if (ticket > 0) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖出第" + ticket + "张票");
            ticket--;
        }else {
            return true;
        }
        return false;
    }
}

四、让线程堵塞和唤醒线程

package com.xioayu.threadTest2;

/**
 * Created by hasee on 2019/5/24.
 */
public class Number implements Runnable {
    public  int ticket=100;
    @Override
    public void run() {
        while (true){
            synchronized (this) {
                notifyAll();
                if(ticket>0) {
                    System.out.println(Thread.currentThread().getName() + "卖出第" + ticket + "张票");
                    ticket--;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Number t1=new Number();
        new Thread(t1).start();
        new Thread(t1).start();
    }
}

【结果】

wait():让线程进入堵塞状态,并释放锁,只要不唤醒,一直在堵塞状态。Object类中申明,只能在同步方法块内调用

sleep() :让线程进入堵塞状态,不释放锁,时间结束后自动进入就绪状态,就是其他线程抢占了CPU也得不到锁,只有等该线程再次得到CPU执行结束或者释放锁后其他线程开可能得到锁。Thread类中申明,任何场景都可调用

notify()和notifyAll():唤醒线程,Object类中申明

生成者消费者例子

package com.xioayu.threadTest2;

/**
 * Created by hasee on 2019/5/25.
 */
public class ThreadTest5 {

    public static void main(String[] args) {
        Apple apple=new Apple();
        Consumer c1=new Consumer(apple);
        Producer p1=new Producer(apple);
        Producer p2=new Producer(apple);

        Thread t1=new Thread(c1);
        Thread t2=new Thread(p1);
        Thread t3=new Thread(p2);
        t1.setName("生成者1");
        t2.setName("消费者1");
        t3.setName("消费者2");

        t1.start();
        t2.start();
        t3.start();
    }
}

class Consumer implements Runnable{

    private Apple apple;

    Consumer(Apple apple){
        this.apple=apple;
    }

    @Override
    public void run() {
          while (true){
              try {
                  Thread.sleep(10);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              apple.reduce();
          }
    }


}

class Producer implements Runnable{
    private Apple apple;

    Producer(Apple apple){
        this.apple=apple;
    }
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            apple.add();
        }
    }


}

class Apple{
    private int number=0;

    public synchronized void add(){
       if(number<5){
           number++;
           System.out.println("已供应第"+number+"个苹果");
           notifyAll();
       }else{
           try {
               wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }

    public synchronized void reduce(){
        if(number>0){
            System.out.println("已消费第"+number+"个苹果");
            number--;
            notifyAll();
        }else{
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

五、未来任务

这是JDK5.0之后新增的一种创建线程的方式,让原本返回值为void的线程有了返回值,便于线程之间的通信

package com.xiaoyu.threadTest3;

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

/**
 * Created by hasee on 2019/5/25.
 */
public class FutureTaskTest {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask<List<User>> listFutureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(listFutureTask);
        thread.setName("子线程");
        thread.start();

        try {
            List<User> list=listFutureTask.get();
            for(User user:list){
                System.out.println(user.getUsername()+"---"+user.getPassword());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<List<User>>{

    @Override
    public List<User> call() throws Exception {
        List<User> list=new ArrayList<User>();
        for (int i=0;i<10;i++) {
            Thread.sleep(100);
            User user = new User();
            user.setUsername(i+"");
            user.setPassword(i+"");
            list.add(user);
        }
        return list;
    }
}


class User{
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

结果

六、线程池

package com.xioayu.threadTest2;

import java.util.concurrent.*;

/**
 * Created by hasee on 2019/5/25.
 */
public class ThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
       /* ThreadPoolExecutor service1= (ThreadPoolExecutor) service;
        service1.setCorePoolSize(5);
        service1.setKeepAliveTime();
        service1.setMaximumPoolSize(15);*/
        service.execute(new MyThread());
        Future<Integer> submit = service.submit(new MyThread2());
        try {
            Integer integer = submit.get();
            System.out.println("返回值"+integer);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        service.shutdown();
    }
}

class MyThread implements Runnable{

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


}

class MyThread2 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        for (int i=1;i<100;i=i+2){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        return 3;
    }
}

execute:实现Runnable接口

submit:实现Callable接口

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值