java多线程

一、线程、进程、多线程

同时执行多个事情
进程是系统分配的,数量受限(程序运行起来就变成进程了)
进程中有多个线程(数量上不受限),按照时间轮转发进行切换
在这里插入图片描述
sleep(): 强迫一个线程睡眠N毫秒。
yield: 线程礼让,让出当前资源,大家重新竞争
isAlive(): 判断一个线程是否存活。
join(): 给其他线程加塞,自己插队执行,直到结束
activeCount(): 程序中活跃的线程数。
enumerate(): 枚举程序中的线程。
currentThread(): 得到当前线程。
isDaemon(): 一个线程是否为守护线程。
setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束) ,垃圾回收,主线程,日志等都是主线程。;用户线程结束,守护线程结束(虚拟机不用等待守护线程结束)
setName(): 为线程设置一个名称。
wait(): 强迫一个线程等待。
notify(): 通知一个线程继续运行。
notifyAll(): 通知其他所有等待该竞争资源的线程
setPriority(): 设置一个线程的优先级。只是提高了该县城的调度概率
suspend() 使线程进入阻塞态,必须resume()方法被调用,才能使线程重新进入可执行状态
volatile :共享资源的安全

二、main主线程、gc垃圾回收线程

  • 都是守护线程

三、继承thread方法实现多线程(本质也是实现Runnable)

在这里插入图片描述

public class TestThread_01 extends Thread {
    @Override
    public void run() {
        for(int i = 1; i<6; i++){
            System.out.println("我在执行线程!");
        }
    }
    public static void main(String[] args){
        TestThread_01 t1 = new TestThread_01();
        t1.start();
        for(int i = 1; i<100; i++){
            System.out.println("我是main方法,主线程");
        }
    }
} 
  • 案例(下载图片)
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestThread_02 extends Thread{
    private String url; //下载地址
    private String name; // 保存文件名

    public TestThread_02 (String url, String name) {
        this.url=url;
        this.name= name;
    }

    @Override
    public void run() {
        new WebDownload().download(url, name);
    }

    public static void main(String[] args){
        new TestThread_02("http://img3.imgtn.bdimg.com/it/u=988449024,2456755617&amp;fm=15&amp;gp=0.jpg", "1.jpg").start();
        new TestThread_02("http://img3.imgtn.bdimg.com/it/u=988449024,2456755617&amp;fm=15&amp;gp=0.jpg", "2.jpg").start();
        new TestThread_02("http://img3.imgtn.bdimg.com/it/u=988449024,2456755617&amp;fm=15&amp;gp=0.jpg", "3.jpg").start();
    }
}

class  WebDownload{
    public void download(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、Runnable创建多线程(推荐,数据可共享的)

public class TestThread_03 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i<6; i ++){
            System.out.println("Runnable线程在跑");
        }
    }
    public static void main(String[] args){
        new Thread(new TestThread_03()).start();
        System.out.println("主线程");
    }
}

五、callable实现多线程

可以监视线程执行的结果

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean> {
    private String url; //下载地址
    private String name; // 保存文件名

    public TestCallable (String url, String name) {
        this.url=url;
        this.name= name;
    }
    @Override
    public Boolean call() throws Exception {
        new WebDownload().download(url, name);
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1 = new TestCallable("http://a3.att.hudong.com/68/61/300000839764127060614318218_950.jpg", "1.jpg");
        TestCallable t2 = new TestCallable("http://a3.att.hudong.com/68/61/300000839764127060614318218_950.jpg", "2.jpg");
        TestCallable t3 = new TestCallable("http://a3.att.hudong.com/68/61/300000839764127060614318218_950.jpg", "3.jpg");
        // 创建执行服务
        ExecutorService es = Executors.newFixedThreadPool(3);
        // 提交执行
        Future<Boolean> result1 = es.submit(t1);
        Future<Boolean> result2 = es.submit(t2);
        Future<Boolean> result3 = es.submit(t3);

        // 获取执行结果
        Boolean r1 = result1.get();
        Boolean r2 = result2.get();
        Boolean r3 = result3.get();
        es.shutdown();

    }
}
class  WebDownloads{
    public void download(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

六、静态代理

public class StaticProxy {
    public static void main(String[] args){
        CompnanyProxy compnanyProxy = new CompnanyProxy(new You());
        compnanyProxy.getmarry();

    }
}


interface Marry{
    void getmarry();
}

class You implements Marry{
    @Override
    public void getmarry() {
        System.out.println("今天可以结婚了");
    }
}


class CompnanyProxy implements Marry{
    private Marry target;

    public CompnanyProxy(Marry target){
        this.target = target;
    }
    @Override
    public void getmarry() {
        before();
        this.target.getmarry();
        after();
    }

    private void after() {
        System.out.println("生孩子");
    }

    private void before() {
        System.out.println("布置新房");
    }

}

七、建议使用标志位,正常停止线程,不推荐使用stop/destory等方法

1 ) 使用标志位

2)使用stop()方法,但该方法就像关掉电脑电源一样,可能会发生预料不到的问题

3)使用中断interrupt()

public class Thread {
    // 中断当前线程
    public void interrupt();
    // 判断当前线程是否被中断
    public boolen isInterrupt();
    // 清除当前线程的中断状态,并返回之前的值
    public static boolen interrupted();   
}

八、线程同步(队列和锁)

1.共享数据不安全的演示
1.1买票
/**
 * 共享数据不安全的演示
 */
public class UnsafeBuyTicket {
    public static void main(String[] args){
        BuyTicket station = new BuyTicket();
        new Thread(station, "黄牛").start();
        new Thread(station, "别人").start();
        new Thread(station, "我").start();
    }

}

class BuyTicket implements Runnable {
    private int num = 10;
    boolean flag = true;
    @Override
    public void run() {
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        if(num<=0) {
            flag = false;
            return;
        }
        Thread.sleep(200);
        System.out.println(Thread.currentThread().getName()+ "拿到"+ num --);
    }
}
1.2 取钱
public class UnsafeBank {
    public static void main(String[] args){
        Account account = new Account("结婚基金", 100);
        Drawing you = new Drawing(account, 50, "我");
        Drawing wife = new Drawing(account, 80, "老婆");
        you.start();
        wife.start();
    }
}
class Account{
    String name; // 卡名
    int money; // 余额

    public Account(String name, int money) {
        this.name = name;
        this.money = money;
    }
}

// 银行模拟取款
class Drawing extends Thread{
    Account account;
    // 去了多少钱
    int drawingMoney;
    // 现在手里有多少钱
    int nowMoney;
    public Drawing(Account account, int drawingMoney, String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
        this.nowMoney = nowMoney;
    }

    @Override
    public void run() {
        if(account.money-drawingMoney<0){
            System.out.println(this.getName() + "余额不足,取不到");
            return;
        }
        try {
            this.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 余额
        account.money = account.money - drawingMoney;
        // 你手里的钱
        nowMoney = nowMoney + drawingMoney;
        System.out.println(account.name + "余额为:" + account.money);
        System.out.println(this.getName() + "手里共有:" + nowMoney);
    }
}
1.3 线程不安全的集合
import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args){
        List<String> list = new ArrayList<>();
        for (int i=0; i<10000; i++) {
            new Thread(() ->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}

线程安全的集合:

Vector:就比Arraylist多了个同步化机制(线程安全)。
Hashtable:就比Hashmap多了个线程安全。
ConcurrentHashMap:是一种高效但是线程安全的集合。
Stack:栈,也是线程安全的,继承于Vector。

除了早期的集合:后期出现的集合都是线程不安全的;Collections工具类中提供了相应的包装方法把它们包装成线程安全的集合

List<E> synArrayList = Collections.synchronizedList(new ArrayList<E>());
Set<E> synHashSet = Collections.synchronizedSet(new HashSet<E>());
Map<K,V> synHashMap = Collections.synchronizedMap(new HashMap<K,V>());
...

JUC并发编程中的CopyOnWriteArrayList和CopyOnWriteArraySet
它们是加了写锁的ArrayList和ArraySet,锁住的是整个对象,但读操作可以并发执行

除此之外还有ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等,至于为什么没有ConcurrentArrayList,原因是无法设计一个通用的而且可以规避ArrayList的并发瓶颈的线程安全的集合类,只能锁住整个list,这用Collections里的包装类就能办到

2.安全锁演示synchronized

synchronized(谁变锁谁)同步会降低执行效率

2.1 买票(synchronized)
/**
 * 共享数据不安全的演示
 */
public class UnsafeBuyTicket {
    public static void main(String[] args){
        BuyTicket station = new BuyTicket();
        new Thread(station, "黄牛").start();
        new Thread(station, "别人").start();
        new Thread(station, "我").start();
    }

}

class BuyTicket implements Runnable {
    private int num = 10;
    boolean flag = true;
    @Override
    public void run() {
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized void buy() throws InterruptedException {
        if(num<=0) {
            flag = false;
            return;
        }
        Thread.sleep(200);
        System.out.println(Thread.currentThread().getName()+ "拿到"+ num --);
    }
}
2.2 取钱演示
public class UnsafeBank {
    public static void main(String[] args){
        Account account = new Account("结婚基金", 100);
        Drawing you = new Drawing(account, 50, "我");
        Drawing wife = new Drawing(account, 80, "老婆");
        you.start();
        wife.start();
    }
}
class Account{
    String name; // 卡名
    int money; // 余额

    public Account(String name, int money) {
        this.name = name;
        this.money = money;
    }
}

// 银行模拟取款
class Drawing extends Thread{
    Account account;
    // 去了多少钱
    int drawingMoney;
    // 现在手里有多少钱
    int nowMoney;
    public Drawing(Account account, int drawingMoney, String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
        this.nowMoney = nowMoney;
    }

    @Override
    public void run() {
   		// 锁的是变化的量
        synchronized (account){
            if(account.money-drawingMoney<0){
                System.out.println(this.getName() + "余额不足,取不到");
                return;
            }
            // sleep 放大问题
            try {
                this.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 余额
            account.money = account.money - drawingMoney;
            // 你手里的钱
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.name + "余额为:" + account.money);
            System.out.println(this.getName() + "手里共有:" + nowMoney);
        }
    }
}

2.3 集合

import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i=0; i<10000; i++) {
            new Thread(() ->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}

2.3 集合加锁
import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i=0; i<10000; i++) {
            new Thread(() ->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}

九、死锁

  • 多个线程互相持有对方所需要的资源,形成僵持
public class DeadLock {
    public static void main(String[] args){
        MakeUp g1 = new MakeUp(0, "灰姑娘");
        MakeUp g2 = new MakeUp(1, "大富婆");
        g1.start();
        g2.start();
    }
}

// 口红
class Lipstick{}

// 镜子
class Mirror{ }

// 化妆
class MakeUp extends Thread{
    // 重要的资源只有一个
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    int choice; // 选择
    String girlName; // 使用化妆品的人

    MakeUp(int choice, String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }
    @Override
    public void run() {
        // 化妆
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //化妆
    private void makeup() throws InterruptedException {
        if(choice==0){
            synchronized (lipstick){
                System.out.println(this.girlName + "获得口红锁");
                sleep(1000);
            }
            synchronized (mirror){
                System.out.println(this.girlName + "获得镜子");
            }
        }else{
            synchronized (mirror){
                System.out.println(this.girlName + "获得镜子");
                sleep(2000);
            }
            synchronized (lipstick){
                System.out.println(this.girlName + "获得口红锁");
            }
        }
    }
}

1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。这样会导致CPU的吞吐量下降。所以死锁情况是会浪费系统资源和影响计算机的使用性能的。那么,解决死锁问题就是相当有必要的了。

十、lock(锁) jDK1.5新增的锁

ReentrantLock 实现了Lock,在实现现成的安全中比较常用,可以显示的添加、释放锁

import java.util.concurrent.locks.ReentrantLock;

// 测试lock锁
public class TestLock {
    public static void main(String[] args){
        TestLock2 testLock2 = new TestLock2();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();

    }
}

class TestLock2 implements Runnable{
    int num =18;
    // 定义lock锁
    private ReentrantLock reentrantLock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try {
                reentrantLock.lock();
                if(num>0) {
                        Thread.sleep(1000);
                    System.out.println(num--);
                }else {
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                reentrantLock.unlock();
            }
        }
    }
}

十一、线程间的通信

生产者消费者(生产者和消费者共享同一个资源)
1.1 管程法
// 生产者消费者通信: 利用缓冲区解决(管程法)
// 生产者、消费者、产品、缓冲区
public class TestPC {
    public static void main(String[] args){
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Customer(container).start();
    }
}
// 生产者
class Productor extends Thread{
    SynContainer container;
    public Productor(SynContainer container){
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                container.push(new Chicken(i));
                System.out.println("生产了第" +i+ "只鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
// 消费者
class Customer extends Thread{
    SynContainer container;
    public Customer(SynContainer container){
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Chicken pop = null;
            try {
                pop = container.pop();
                System.out.println("消费了第" +pop.name+ "只鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
// 产品
class Chicken{
    int name;

    public Chicken(int name) {
        this.name = name;
    }
}

// 缓冲区
class SynContainer{
    Chicken[] chickens = new Chicken[10];
    int count = 0;
    // 生产者生产产品
    public synchronized void push(Chicken chicken) throws InterruptedException {
        // 如果容器满了就通知消费者进行消费
        if(count==chickens.length){
            // 容器满了,生产等待
            this.wait();
        }
        chickens[count] = chicken;
        count ++ ;
        // 通知消费
        this.notify();
    }

    // 消费者消费产品
    public synchronized Chicken pop() throws InterruptedException {
        // 判断能否消费
        if(count==0){
            // 等待生产者生产,消费等待
            this.wait();
        }
        count -- ;
        Chicken chicken = chickens[count];
        // 吃完了通知生产者生产
        this.notify();
        return chicken;
    }
}
1.2 信号灯法

十二、线程池

管理线程并发数量/提高线程使用效率、提高运行速度

1. ExecutorService 和 Excutors

在这里插入图片描述
在这里插入图片描述

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 创建连接池
        ExecutorService es = Executors.newFixedThreadPool(3);
        // 执行
        es.execute(runnable);
        es.execute(runnable);
        es.execute(runnable);
        es.execute(runnable);
        es.execute(runnable);
        // 关闭连接
        es.shutdown();
    }
}

2. ThreadPoolExecutor

线程池参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值