Java笔记_基础_线程

创建线程方法① 继承Thread

继承Thread 重写run()方法
调用启动: 创建对象.start:();

方法返回值说明
(static)sleep(int i)void睡眠 i 毫秒
(static)currentThread()void返回当前正在执行的线程,可直接 getName
getPriority()int获取优先值 返回int
getName()String获取对象名
setName(String str)void给当前线程对象起名
setPriority(int i)voidi:1~10 优先级值 越高表示CPU优先执行概率越高(概率!)
setDeomon()void将对象线程标记为附属线程,当没有非附属线程运行时,附属线程将自动结束
public class Demo {
    public static void main(String[] args) throws Exception {
        Demo1 d = new Demo1();
        d.start(); //开启新线程
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程执行了");
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

class Demo1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("新线程执行了");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了

创建线程方法② 实现Runnable接口

实现Runnable接口 重写run()方法
调用启动: Thread对象有参构造 创建对象.start:();

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo1 d = new Demo1();
        Thread t = new Thread(d);
        t.start(); //开启新线程
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程执行了");
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

class Demo1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("新线程执行了");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Lambda表达式 与上方代码完全相同

public class Demo {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> { //使用Lambda表达式匿名内部类 实现Runnable接口 重写run();
            for (int i = 0; i < 5; i++) {
                System.out.println("新线程执行了");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        t.start(); //开启新线程
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程执行了");
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了

创建线程方法③ 实现Callable接口

可以获取线程返回值
实现Callable<返回值类型>接口 重写call()方法
调用启动: FutureTask<返回值类型>有参构造创建对象 Thread对象有参构造创建对象.start:();
FutureTask<返回值类型>对象.get(): 等待线程运行结束,返回运行结果

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

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo1 d = new Demo1();
        FutureTask<String> f = new FutureTask<>(d); //泛型与参数的返回值类型一致
        Thread t = new Thread(f);
        t.start(); //开启新线程
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程执行了");
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String s = f.get();
        System.out.println("主线程: 新线程的返回值为" + s);
    }
}

class Demo1 implements Callable<String> {

    @Override
    public String call() throws Exception { //此处返回值为 Callable 的泛型
        for (int i = 0; i < 5; i++) {
            System.out.println("新线程执行了");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "Demo1";
    }
}

运行结果:

主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了
新线程执行了
主线程执行了
新线程执行了
主线程: 新线程的返回值为Demo1

线程池

Executors

尽量避免使用此方法创建线程池

方法返回值说明
(static)newCachedThreadPool()构造方法创建一个默认线程池
(static)newFixedThreadPool(int i)构造方法创建一个有上限的线程池
submit(Runnable r)void开启线程,当线程池中有空线程将不再新建,使用空线程
shutdown()void关闭线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newCachedThreadPool();
        System.out.println("主线程执行了");

        es.submit(() -> {
            System.out.println(Thread.currentThread().getName());
            
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        es.submit(() -> System.out.println(Thread.currentThread().getName()));
        Thread.sleep(1000);
        es.submit(() -> System.out.println(Thread.currentThread().getName()));

        es.shutdown();
        System.out.println("主线程结束了");
    }
}

构造方法:

主线程执行了
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
主线程结束了

ThreadPoolExecutor

可以指定规则的线程池
用法同Executors

构造方法: ThreadPoolExecutor(核心线程数, 最大线程数, 空闲线程存活时间, 时间单位, 阻塞队列, 线程工厂, 拒绝策略)

参数类型说明
核心线程数int大于0
最大线程数int大于核心线程数
空闲线程存活时间int大于0
时间单位TimeUnitTimeUnit.SECONDS:秒 / DAYS天 / HOURS小时 / MINUTES分钟 / MILLISECONDS毫秒
阻塞队列ArrayBlockingQueuenew ArrayBlockingQueue<>(int i): 当核心线程满了将存至队列,当队列满了将创建新线程,当线程达到最大值时,将启动拒绝策略
线程工厂ExecutorsExecutors.defaultThreadFactory(): 创建默认线程
拒绝策略ThreadPoolExecutornew ThreadPoolExecutor.AbortPolicy(): 丢弃任务并抛出异常 / DiscardPolicy(): 丢弃任务(不推荐) / DiscardOldestPolicy(): 丢弃队列中等待最久的任务 / CallerRunsPolicy(): 绕过线程直接执行
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo {
    public static void main(String[] args) throws Exception {
        ThreadPoolExecutor es = new ThreadPoolExecutor(2, 3, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        System.out.println("主线程执行了");

        es.submit(() -> {
            System.out.println(Thread.currentThread().getName());

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        es.submit(() -> System.out.println(Thread.currentThread().getName()));
        Thread.sleep(1000);
        es.submit(() -> System.out.println(Thread.currentThread().getName()));

        es.shutdown();
        System.out.println("主线程结束了");
    }
}

运行结果:

主线程执行了
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
主线程结束了

线程操作

CountDownLatch

控制一个线程等待其他线程各自执行完毕后再执行

方法返回值说明
CountDownLatch(int i)构造方法原理为计数器,初始为 i ,每当一个线程执行完毕计数器 -1 ,当计数器为 0 时,唤醒所有等待中的线程
await()void使当前线程等待,当计数器为0时唤醒
countDown()void表示线程执行完毕
import java.util.concurrent.CountDownLatch;

public class Demo {

    private static CountDownLatch c = new CountDownLatch(2);

    public static void main(String[] args) throws Exception {

        Thread t1 = new Thread(() -> { //新线程 1
            try {
                Thread.sleep(2000); //等待2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("新线程 1: 执行了");
            c.countDown();
        });

        Thread t2 = new Thread(() -> { //新线程 2
            System.out.println("新线程 2: 执行了");
            try {
                Thread.sleep(2000); //等待2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            c.countDown();
        });

        t1.start(); //开启新线程 1
        t2.start(); //开启新线程 2
        System.out.println("主线程: 执行了");
        c.await();
        System.out.println("主线程: 两条新线程执行完毕");
    }
}

运行结果:

主线程: 执行了
新线程 2: 执行了
新线程 1: 执行了
主线程: 两条新线程执行完毕

Semaphore

控制同时执行的线程数量

Semaphore(int i) | | 原理为计数器,初始为 i ,允许同时执行的线程数量, i 为 0 则不允许获取执行权限
acquire() | | 获取执行权限 i-1
release() | | 归还执行权限 i+1

import java.util.concurrent.Semaphore;

public class Demo {

    private static Semaphore s = new Semaphore(3);

    public static void main(String[] args) throws Exception {

        Thread t1 = new Thread(() -> { //新线程 1
            try {
                s.acquire();
                System.out.println("新线程 1: 执行了");
                Thread.sleep(2000); //等待2秒
                System.out.println("新线程 1: 执行完毕");
                s.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> { //新线程 2
            try {
                s.acquire();
                System.out.println("新线程 2: 执行了");
                Thread.sleep(2000); //等待2秒
                System.out.println("新线程 2: 执行完毕");
                s.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        Thread t3 = new Thread(() -> { //新线程 3
            try {
                s.acquire();
                System.out.println("新线程 3: 执行了");
                Thread.sleep(2000); //等待2秒
                System.out.println("新线程 3: 执行完毕");
                s.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        Thread t4 = new Thread(() -> { //新线程 4
            try {
                s.acquire();
                System.out.println("新线程 4: 执行了");
                Thread.sleep(2000); //等待2秒
                System.out.println("新线程 4: 执行完毕");
                s.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        Thread t5 = new Thread(() -> { //新线程 5
            try {
                s.acquire();
                System.out.println("新线程 5: 执行了");
                Thread.sleep(2000); //等待2秒
                System.out.println("新线程 5: 执行完毕");
                s.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        System.out.println("主线程: 执行了");
    }
}

运行结果:

主线程: 执行了
新线程 3: 执行了
新线程 1: 执行了
新线程 2: 执行了
新线程 3: 执行完毕
新线程 2: 执行完毕
新线程 1: 执行完毕
新线程 4: 执行了
新线程 5: 执行了
新线程 4: 执行完毕
新线程 5: 执行完毕

可以看到最多同时执行 3 条线程,即使中间等待了 2秒 ,其他线程也无法执行

安全问题

在不同线程同时操作一个数据,可能会出现线程安全问题

抢票案例:

public class Demo {

    public static int tickets = 10; //一共10张票

    public static void main(String[] args) throws Exception {
        new Demo1().start();
        new Demo1().start();
        new Demo1().start();
        new Demo1().start();
        new Demo1().start(); //开启5个抢票线程
        Thread.sleep(5000);
    }
}

class Demo1 extends Thread {
    @Override
    public void run() {
        while (true) {
            if (Demo.tickets > 0) {
                System.out.println("线程" + Thread.currentThread().getName() + ": 抢票");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Demo.tickets = Demo.tickets - 1;
                System.out.println("线程" + Thread.currentThread().getName() + ": 抢到了,还有" + Demo.tickets + "张");
            } else {
                System.out.println("线程" + Thread.currentThread().getName() + ": 没票了");
                break;
            }
        }
    }
}

运行结果:

线程Thread-4: 抢票
线程Thread-3: 抢票
线程Thread-2: 抢票
线程Thread-1: 抢票
线程Thread-0: 抢票
线程Thread-2: 抢到了,还有6张
线程Thread-1: 抢到了,还有6张
线程Thread-3: 抢到了,还有6张
线程Thread-0: 抢到了,还有6张
线程Thread-0: 抢票
线程Thread-4: 抢到了,还有6张
线程Thread-4: 抢票
线程Thread-3: 抢票
线程Thread-1: 抢票
线程Thread-2: 抢票
线程Thread-1: 抢到了,还有3张
线程Thread-1: 抢票
线程Thread-0: 抢到了,还有1张
线程Thread-0: 抢票
线程Thread-3: 抢到了,还有2张
线程Thread-3: 抢票
线程Thread-2: 抢到了,还有3张
线程Thread-2: 抢票
线程Thread-4: 抢到了,还有2张
线程Thread-4: 抢票
线程Thread-4: 抢到了,还有-1张
线程Thread-4: 没票了
线程Thread-2: 抢到了,还有-2张
线程Thread-2: 没票了
线程Thread-0: 抢到了,还有-2张
线程Thread-0: 没票了
线程Thread-1: 抢到了,还有-3张
线程Thread-1: 没票了
线程Thread-3: 抢到了,还有-2张
线程Thread-3: 没票了

很明显不可能还剩-2张票

线程锁

synchronized(任意对象){ 共享数据操作代码块 }

将代码块锁上,参数对象相当于钥匙,只有一把钥匙,即被相同锁锁上的代码同一时间只能有一份在执行

public class Demo {

    public static int tickets = 10; //一共10张票

    public static String s = "一个字符串";

    public static void main(String[] args) throws Exception {
        new Demo1().start();
        new Demo1().start();
        new Demo1().start();
        new Demo1().start();
        new Demo1().start(); //开启5个抢票线程
        Thread.sleep(5000);
    }
}

class Demo1 extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Demo.s) { //使用一个字符串对象当锁
                if (Demo.tickets > 0) {
                    System.out.println("线程" + Thread.currentThread().getName() + ": 抢票");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Demo.tickets = Demo.tickets - 1;
                    System.out.println("线程" + Thread.currentThread().getName() + ": 抢到了,还有" + Demo.tickets + "张");
                } else {
                    System.out.println("线程" + Thread.currentThread().getName() + ": 没票了");
                    break;
                }
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

线程Thread-0: 抢票
线程Thread-0: 抢到了,还有9张
线程Thread-4: 抢票
线程Thread-4: 抢到了,还有8张
线程Thread-3: 抢票
线程Thread-3: 抢到了,还有7张
线程Thread-2: 抢票
线程Thread-2: 抢到了,还有6张
线程Thread-1: 抢票
线程Thread-1: 抢到了,还有5张
线程Thread-2: 抢票
线程Thread-2: 抢到了,还有4张
线程Thread-3: 抢票
线程Thread-3: 抢到了,还有3张
线程Thread-4: 抢票
线程Thread-4: 抢到了,还有2张
线程Thread-0: 抢票
线程Thread-0: 抢到了,还有1张
线程Thread-4: 抢票
线程Thread-4: 抢到了,还有0张
线程Thread-3: 没票了
线程Thread-2: 没票了
线程Thread-1: 没票了
线程Thread-0: 没票了
线程Thread-4: 没票了

ReentrantLock

方法返回值说明
Lock()void获得锁
tryLock()void尝试获得锁
unLock()void释放锁

虚拟机中线程的六种状态:

NEW ( 新建 ) -> 创建线程对象
RUNNABLE ( 就绪 ) -> start();
BLOCKED ( 阻塞 ) -> 无法进入被锁对象
WAITING ( 等待 ) -> wait();
TIME_WAITING ( 计时 ) -> sleep();
TERMINATED ( 结束 ) -> 运行完毕

原子性

原子性操作有: ①除long和double之外的原始类型的赋值 ②java.concurrent.Atomic.*类的操作

AtomicInteger

以原子方式操作int

方法返回值说明
AtomicInteger()构造方法初始化默认值为0
AtomicInteger(int i)构造方法初始化为 i
get()int获取值
getAndIncrement()int以原子方式自增1 返回自增前
incrementAndGet()int以原子方式自增1 返回自增后
addAndGet(int i)int以原子方式增加i 返回结果
getAndSet(int i)int以原子方式改为i 返回旧

Hashtable: 用法同HashMap 底层synchronized加HashMap(效率较低)
ConcurrentHashMap: 用法同HashMap(效率较高)

BlockingQueue

阻塞队列

方法返回值说明
ArrayBlockingQueue构造方法底层数组,有界
LinkedBlockingQueue构造方法底层链表.无界
put(T t)void存入元素 /类似集合,但若存入时队列满了则等待队列有空余再存入
take()T取出元素 /类似集合,但若取出时队列为空则等待队列有内容时再取出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值