JAVA多线程
1 多线程的实现方式
package com.qf.a_thread;
/**
* 进程:正在启动的应用程序,比如启动后的QQ
* 线程:进程中正在执行的一条执行路径,依托与进程,比如QQ中接受别人的信息
* 进程与线程的区别:
* 1 进程是操作系统在资源上的基本分配,线程是CPU时间片执行的基本单位
* 2 线程包含于进程,依托于进程,而进程则至少有一条后台线程,一般进程内部是多条线程并发执行
* 3 进程资源独立,线程资源在同一进程内部是共享的
*
* 线程创建方式:
* 1 创建一个类,继承Thread类,测试方法中实例化该对象并调用该对象的start方法
* 2 创建一个类,实现Runnable接口,测试方法中实例化Thread对象,传入该类对象,再调用
* Thread对象的start方法(可通过匿名内部类实现)
*/
public class ThreadTest {
public static void main(String[] args) {
// 子线程1 -> 继承Thread类
new MyThread().start();
// 子线程2 -> 实现Runnable接口
new Thread(new MyRun()).start();
// 子线程3 -> 匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("子线程3-->"+i);
}
}
}).start();
for(int i=0;i<100;i++) {
System.out.println("守护线程-->"+i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("子线程1-->"+i);
}
}
}
class MyRun implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("子线程2-->"+i);
}
}
}
2 多线程的常用方法
2.1 sleep - 休眠
package com.qf.b_method;
/**
* 线程常用方法
* sleep - 休眠
*/
public class SleepTest {
public static void main(String[] args) throws InterruptedException {
new MyThread().start();
// 主线程休眠1ms
Thread.sleep(1);
for(int i=0;i<100;i++) {
System.out.println("主线程..."+i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
// 子线程休眠1ms
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for(int i=0;i<100;i++) {
System.out.println("子线程..."+i);
}
}
}
2.2 yeild - 礼让
package com.qf.b_method;
/**
* yeild - 礼让
* 结束本次运行状态,进入就绪状态,与其他线程进行下一次资源的争抢
*/
public class YeildTest {
public static void main(String[] args) {
new MyThreadA().start();
new MyThreadB().start();
}
}
class MyThreadA extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("线程A..."+i);
// 打印一次,礼让一次
Thread.yield();
}
}
}
class MyThreadB extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("线程B..."+i);
}
}
}
2.3 priority - 优先级
package com.qf.b_method;
/**
* setPriority - 设置优先级
*/
public class PriorityTest {
public static void main(String[] args) throws InterruptedException {
MyThread2 thread1 = new MyThread2();
thread1.setName("线程A");
thread1.setPriority(Thread.MAX_PRIORITY);
thread1.start();
MyThread2 thread2 = new MyThread2();
thread2.setName("线程B");
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.start();
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++) {
// System.out.println(super.getName()+"..."+i);
// 当前类若实现Runnable接口时可使用下面方法获取名字
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}
2.4 join - 插入
package com.qf.b_method;
/**
* join - 插队,可插入其他线程中,一旦插入,插入的线程执行完后再执行被插入线程
*/
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
MyTh th = new MyTh();
th.start();
for(int i=0;i<100;i++) {
System.out.println("主线程..."+i);
if(i==10) {
th.join();
}
}
}
}
class MyTh extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("子线程..."+i);
}
}
}
3 多线程的安全
- 安全介绍
package com.qf.c_safe;
import java.util.Arrays;
/**
* 线程安全
* synchronized - 同步锁 synchronized(this){} 代码块或方法
*/
public class Test {
public static void main(String[] args) {
Runnable run = new MyRun();
new Thread(run,"Hello").start();
new Thread(run,"World").start();
}
}
class MyRun implements Runnable{
private String[] strs = new String[5];
private int i;
@Override
public void run() {
// 获取当前线程对象的名称(这里是两个线程,所以有两个)
String name = Thread.currentThread().getName();
// 锁住run对象(这里只有一个任务,所以有一个)
synchronized (this) {
strs[i] = name;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
System.out.println(Arrays.toString(strs));
}
}
}
- 测试代码1
package com.qf.c_safe;
/**
* 线程安全,卖票(锁住代码块)
*/
public class TicketTest {
public static void main(String[] args) {
Runnable task = new Task();
for(int i=1;i<=5;i++) {
new Thread(task,"窗口"+i).start();
}
}
}
class Task implements Runnable{
private int ticket = 1000;
@Override
public void run() {
while(true) {
synchronized (this) {
if(ticket > 0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票...");
ticket--;
}else {
System.out.println(Thread.currentThread().getName()+"票已卖完!");
break;
}
}
}
}
}
- 测试代码2
package com.qf.c_safe;
/**
* 线程安全,卖票(锁住方法)
*/
public class Ticket2Test {
public static void main(String[] args) {
Runnable task = new Task2();
for(int i=1;i<=5;i++) {
new Thread(task,"窗口"+i).start();
}
}
}
class Task2 implements Runnable{
private int ticket = 1000;
@Override
public void run() {
while(true) {
if(save()) {
break;
}
}
}
public synchronized boolean save() {
if(ticket > 0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票...");
ticket--;
return false;
}
System.out.println(Thread.currentThread().getName()+"票已卖完!");
return true;
}
}
- 测试代码3
package com.qf.c_safe;
/**
* 线程安全,卖票(锁住代码块)
*/
public class Ticket3Test {
public static void main(String[] args) {
for(int i=1;i<=5;i++) {
MyThread thread = new MyThread();
thread.setName("窗口"+i);
thread.start();
}
}
}
class MyThread extends Thread{
private static int ticket = 1000;
@Override
public void run() {
while(true) {
synchronized ("lock") { // 字符串字面量对象,存放在常量池中,只维护一份
if(ticket > 0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票...");
ticket--;
}else {
System.out.println(Thread.currentThread().getName()+"票已卖完!");
break;
}
}
}
}
}
- 测试代码4
package com.qf.c_safe;
/**
* 线程安全,卖票(锁住方法)
*/
public class Ticket4Test {
public static void main(String[] args) {
for(int i=1;i<=5;i++) {
MyThread2 thread = new MyThread2();
thread.setName("窗口"+i);
thread.start();
}
}
}
class MyThread2 extends Thread{
private static int ticket = 1000;
@Override
public void run() {
while(true) {
if(safe()) { // static方法通过类名调用,独一份
break;
}
}
}
public synchronized static boolean safe() {
if(ticket > 0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票...");
ticket--;
return false;
}else {
System.out.println(Thread.currentThread().getName()+"票已卖完!");
return true;
}
}
}
4 死锁
package com.qf.d_dead;
/**
* 死锁
*/
public class Test {
public static void main(String[] args) {
new MyThread(true).start();
new MyThread(false).start();
}
}
class MyThread extends Thread{
private boolean flag;
public MyThread() {
}
public MyThread(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag) {
synchronized ("A") {
System.out.println("A......1......");
synchronized ("B") {
System.out.println("B......1......");
}
}
}else {
synchronized ("B") {
System.out.println("B......2......");
synchronized ("A") {
System.out.println("A......2......");
}
}
}
}
}
5 线程的等待和唤醒
- 仓库
package com.qf.e_wait;
/**
* 仓库
*/
public class Store {
private int num;
public void push() throws InterruptedException {
synchronized (this) {
if(num >= 20) {
wait(); // 线程的等待
}
num++;
System.out.println("正在生产第"+num+"个件货...");
notify(); // 线程的唤醒
}
}
public void pop() throws InterruptedException {
synchronized (this) {
if(num <= 0) {
wait(); // 线程的等待
}
System.out.println("正在消费第"+num+"个件货...");
num--;
notify(); // 线程的唤醒
}
}
}
- 生产者
package com.qf.e_wait;
/**
* 生产者
*/
public class Productor extends Thread {
private Store store;
public Productor() {}
public Productor(Store store) {
this.store = store;
}
@Override
public void run() {
while(true) {
try {
store.push();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 消费者
package com.qf.e_wait;
/**
* 消费者
*/
public class Customtor extends Thread {
private Store store;
public Customtor() {}
public Customtor(Store store) {
this.store = store;
}
@Override
public void run() {
while(true) {
try {
store.pop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 测试类
package com.qf.e_wait;
/**
* 测试
*/
public class Test {
public static void main(String[] args) {
Store store = new Store();
new Productor(store).start();
new Customtor(store).start();
}
}
6 线程池
- 主代码
package com.qf.a_pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池
* - 提供可固定的线程数量,减少线程创建和销毁的次数,极大提高了性能
*/
public class Test {
public static void main(String[] args) {
// 1 创建一个固定的线程池
// ExecutorService es = Executors.newFixedThreadPool(2);
// 1 创建一个带缓冲的线程池
ExecutorService es = Executors.newCachedThreadPool();
// 2 将线程池中线程对象分配给任务
Runnable myRun = new MyRun();
es.submit(myRun);
es.submit(myRun);
es.submit(myRun);
// 3 关闭线程池
es.shutdown();
}
}
class MyRun implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"......"+i);
}
}
}
7 重入锁
- 主代码
package com.qf.b_lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Lock: 重入锁,等同于synchronized
*/
public class MyLock {
private Lock lock = new ReentrantLock();
private String[] strs = {"A","B","","",""};
private int count = 2;
public void add(String value) {
lock.lock();
try {
strs[count] = value;
count++;
} finally {
lock.unlock();
}
}
public String[] getStrs() {
return strs;
}
}
8 读写锁
- 主代码
package com.qf.c_readwrite_lock;
/**
* 读写锁
* - 与重入锁相比,读远大于写的情况下性能占优
*/
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
public class MyClass {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReadLock readLock = lock.readLock();
WriteLock writeLock = lock.writeLock();
private int value;
// 读
public int getValue() {
readLock.lock();
try {
return this.value;
} finally {
readLock.unlock();
}
}
// 写
public void setValue(int value) {
writeLock.lock();
try {
this.value = value;
} finally {
writeLock.unlock();
}
}
}
9 线程安全的集合
9.1 线程安全的List集合
- 主代码
package com.qf.d_saft_collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* CopyOnWriteArrayList,线程安全
*/
public class ListTest {
public static void main(String[] args) {
List<Integer> list = new CopyOnWriteArrayList<>();
for(int i=0;i<5;i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
list.add(temp);
System.out.println(list);
}
}).start();
}
}
}
9.2 线程安全的Set集合
- 主代码
package com.qf.d_saft_collection;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* CopyOnWriteArraySet,线程安全,底层实现是CopyOnWriteArrayList
*/
public class SetTest {
public static void main(String[] args) {
Set<Integer> set = new CopyOnWriteArraySet<>();
for(int i=0;i<5;i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
set.add(temp);
System.out.println(set);
}
}).start();
}
}
}
9.3 线程安全的Map集合
-主代码
package com.qf.d_saft_collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* ConcurrentHashMap: 线程安全
*/
public class MapTest {
public static void main(String[] args) {
Map<String, Integer> map = new ConcurrentHashMap<>();
for(int i=0;i<5;i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
map.put(temp+"", 1);
System.out.println(map);
}
}).start();
}
}
}
9.4 线程安全的队列
9.4.1 普通队列
package com.qf.e_queue;
import java.util.LinkedList;
import java.util.Queue;
/**
* Queue
* - 队列,Collection接口的子接口,先进先出
* - 队列常用方法
*/
public class LinkedListTest {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 元素添加
queue.offer(1);
queue.offer(2);
queue.offer(3);
// 获取一个元素但不移除
Integer one = queue.peek();
System.out.println(queue);
System.out.println(one);
// 获取一个元素并移除
Integer two = queue.poll();
System.out.println(two);
System.out.println(queue);
}
}
9.4.2 并发安全队列
package com.qf.e_queue;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* ConcurrentLinkedQueue
* - 线程安全的队列
*/
public class concurrentLinkedQueueTest {
public static void main(String[] args) throws InterruptedException {
Queue<Integer> queue = new ConcurrentLinkedQueue<>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i=1;i<=5;i++) {
queue.offer(i);
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i=6;i<=10;i++) {
queue.offer(i);
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(queue);
}
}
9.4.3 阻塞队列
package com.qf.e_queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* BlockingQueue
* - 阻塞队列
*/
public class BlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
queue.put(1);
queue.put(2);
queue.put(3);
System.out.println(queue);
queue.take();
queue.put(4);
System.out.println(queue);
}
}