Java 多线程
-
在程序运行 主线程,为系统的入口,用于执行整个程序;
-
在一个进程中,如果开辟了多个线程,线程的运行有调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的;
-
对同一份资源操作时,会财富商城存在资源抢夺的问题,需要加入并发控制;
-
线程会带来额外的开销,如cpu调度时间,并发控制开销;
-
每个线程在自己的工作内存交互,没存控制不当会造成数据不一致
//创建多线程的方法一,继承类法
public class TestThread1 extends Thread{
//继承多线程类后,一定要重写run()方法;
1、网络图片下载
-
下载commons-io第三方包,导入包
-
-
创建线程类,重写run()方法,调用下载图片方法,新建构造函数给新建对象赋值;
-
新建主函数,新建线程对象,调用线程方法start();
//熟悉线程使用,用线程类的经行多进程图片下载
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread2 extends Thread{
public String url;
public String name;
public TestThread2(String url,String name){
this.name = name;
this.url = url;
}
2、Runnable接口线程
-
Runnable接口对比Thread类,避免了单继承的局限性,灵活方便
-
创建类TestThread3,继承Runnable,重写run()方法;
-
新建线程对象testThread3,再新建线程对象thread,把对象testThread3丢到thread里面才能运行
-
调用thread调用start()方法运行
public class TestThread3 implements Runnable{
//Runnable方法实现多线程图片下载
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread2 implements Runnable{
public String url;
public String name;
public TestThread2(String url,String name){
this.name = name;
this.url = url;
}
3、初识并发问题
-
多个线程调用同一个对象
-
有可能会出现调用资源错误,多个线程调用同一个资源
//程序还有问题,因为出现不同人抢到同一张票
public class TestThread4 implements Runnable{
private int number = 10;
4、龟兔赛跑问题(待解决问题:乌龟赢后,兔子还会跑一次)
-
首先来个赛道距离,然后要离终点越来越近;
-
判断比赛是否结束;
-
打印出胜利者;
-
龟兔赛跑开始;
-
故事中是乌龟赢,兔子需要睡觉,所以我们需要模拟兔子睡觉;
-
终于,乌龟赢得比赛
//兔子乌龟赛跑比赛
public class Race implements Runnable {
private static String winner;
5、静态代理模式(多线程的底层实现模拟)
如何创建代理模式:1、创建接口类;2、创建代理类和雇主类都要使用接口类和重写接口类的方法;3、代理类里面需要创建调用雇主类的目标,创建构造函数调用雇主类目标,实现方法需要调用雇主目标,还可以创建更多的方法执行雇主类不能实现的其他功能;4、创建主函数,创建代理对象,代理对象调用雇主目标,实现方法。
-
真时对象和代理对象都要同时实现统一接口
-
代理对象要代理真实对象
-
代理对象可以帮助真实对象做好多他们做不了的事情
-
真实的对象只要专注于做自己的事情就好了
//静态代理模式总结
//真时对象和代理对象都要同时实现统一接口
//代理对象要代理真是对象
//好处
//代理对象可以帮助真实对象做好多他们做不了的事情
//真实的对象只要专注于做自己的事情就好了
public class StaticProxy {
public static void main(String[] args) {
You you = new You();//创建结婚对象
new Thread( ()-> System.out.println("成功了") ).start();//Lambda表达式
new WeddingCompany(you).HappyMarry();;
}
}
interface Marry{
void HappyMarry();
}
//真时角色
class You implements Marry{
6、线程停止
-
建议正常停止
-
设置标志位,正常停止线程
-
不建议使用stop和distroy等过时方法或其他JDK不推荐的方法
/*
1、创建类,继承Runnable接口,设置一个类变量flag,重写run方法
2、创建一个停止方法stop,更改flag的状态
3、创建主方法,新建对象,调用start方法,创建循环,循环调用stop方法,停止线程
*/
public class ThreadStop implements Runnable{
private boolean flag = true;
7、线程休眠sleep
-
倒计时10秒
-
打印当前时间
-
使用sleep记得捕获异常就好
//倒计时10秒
import static java.lang.Thread.sleep;
public class ThreadSleep {
public static void main(String[]args) {
try {
new ThreadSleep().tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void tenDown() throws InterruptedException {
int num = 10;
while(true){
System.out.println(num--);
Thread.sleep(1000);
if(num<=0){
break;
}
}
}
}
//打印当前时间
import java.text.SimpleDateFormat;
import java.util.Date;
import static java.lang.Thread.sleep;
public class ThreadSleep {
public static void main(String[]args) {
Date startTime = new Date(System.currentTimeMillis());
while (true){
try {
Thread.sleep(1000);//休眠一面
//把系统时间转为简单的格式打印
System.out.println(new SimpleDateFormat("hh:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新startTime里面的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
8、线程礼让yield
-
让当前线程暂停,但不阻塞
-
将线程从运行状态转为就绪状态
-
让cpu重新调度,礼让不一定成功,让不让cpu说了算
public class ThreadYield {
public static void main(String[] args) {
//正常运行,礼让成功就是先运行a,再运行b。如不成功就a停止再运行b
new Thread(new MyYield(),"a").start();
new Thread(new MyYield(),"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"暂停运行");
}
}
9、线程插队-Join
-
让当前线程暂停且阻塞
-
插队线程运行结束其他线程才能继续运行
public class ThreadJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("VIP来插队了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
ThreadJoin threadJoin = new ThreadJoin();
Thread thread = new Thread(threadJoin);//插队一定要这样创建对象,
thread.start();//静态代理方法,线程开始运行
for (int i = 0; i < 500; i++) {
if(i==200){
thread.join();//强行插队,并阻塞主线程,该线程运行完主线程才能继续运行
}
System.out.println("主线程运行"+i);
}
}
}
10、线程优先级
-
优先级最高为10,最低为1,主函数线程优先级一般为5
-
并不是优先级高就最先执行,还是要看CPU的心情
//优先级最高为10,最低为1,主函数线程优先级一般为5
//并不是优先级高就最先执行,还是要看cpu的心情
public class ThreadPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+"优先级为:"+Thread.currentThread().getPriority());
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()
+"优先级为:"+Thread.currentThread().getPriority());
ThreadPriority threadPriority = new ThreadPriority();
Thread thread1 = new Thread(threadPriority,"线程一");
Thread thread2 = new Thread(threadPriority,"线程二");
Thread thread3 = new Thread(threadPriority,"线程三");
Thread thread4 = new Thread(threadPriority,"线程四");
Thread thread5 = new Thread(threadPriority,"线程五");
thread1.start();
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.start();
thread3.setPriority(Thread.MAX_PRIORITY);
thread3.start();
thread4.setPriority(5);
thread4.start();
}
}
11、线程守护
-
线程分用户线程和守护线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕,如后台记录操作日志,监控内存,垃圾回收等处理
public class ThreadGuard {
public static void main(String[] args) {
God god = new God();
Human human = new Human();
Thread thread = new Thread(god);
thread.setDaemon(true);//----重点----默认false是用户线程,改为true是守护线程
thread.start();//守护线程启动
new Thread(human).start();//用户线程启动
}
}
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("---------God is guarding------------");
}
}
}
class Human implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("---------Humans is living------------");
}
System.out.println("------------Say Goodbye-------------");
}
}
12、线程同步机制
-
让当前线程暂停,但不阻塞
-
将线程从运行状态转为就绪状态
-
让cpu重新调度,礼让不一定成功,让不让cpu说了算
public class ThreadYield {
public static void main(String[] args) {
//正常运行,礼让成功就是先运行a,再运行b。如不成功就a停止再运行b
new Thread(new MyYield(),"a").start();
new Thread(new MyYield(),"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"暂停运行");
}
}
13、线程同步,安全监控
-
同步块:synchronized(obj){},
-
obj可以是任何对象,建议是需要增删改的对象,才能避免数据混乱
-
同步块的作用是:限制访问该对象,即由线程访问该对象后立即锁住该对象,等访问结束后才会解锁对象给其他线程访问,即控制对象只能给一个线程访问处理。
import java.util.ArrayList;
public class UnsafeList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(100);//有了整个延迟才能锁住,没延迟锁不住啊
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
//安全的集合CopyOnWriteArrayList,不用锁也可以正常运行?
import java.util.concurrent.CopyOnWriteArrayList;
public class ThreadJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
14、死锁和死锁避免方法
-
互斥条件:一个资源每次只能被一个进程调用;
-
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放,请求另外一个资源前,把手里的资源释放
-
不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺;
-
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
public class DeadLock {
public static void main(String[] args) {
Makeup lucy = new Makeup(0, "Lucy");
Makeup mari = new Makeup(1, "Mari");
lucy.start();
mari.start();
}
}
class Mirror{
}
class Lipstick{
}
class Makeup extends Thread{
final static Mirror mirror = new Mirror();//用静态类型,保证程序执行过程中该对象唯一
final static Lipstick lipstick = new Lipstick();
int choice;
String girlName;
Makeup(int choice,String girlName) {//构造函数,创建对象时赋予类初始值
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
try {
makeup();//一定放在run方法里面,makeup()方法不运行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if(choice==0){
synchronized (lipstick){//注意锁里面不能再放锁,一层层锁容易出错,混乱
System.out.println("========口红正在被使用0=======");
Thread.sleep(1000);//被占用1秒
}
synchronized (mirror){
System.out.println("========镜子正在被使用0=======");
}
} else{
synchronized (mirror){
System.out.println("========镜子正在被使用1=======");
Thread.sleep(2000);//被占用2秒
}
synchronized (lipstick){
System.out.println("========口红正在被使用1=======");
}
}
}
}
15、Lock锁
-
可重入锁:ReentrantLock
-
-
public class ThreadYield {
public static void main(String[] args) {
//正常运行,礼让成功就是先运行a,再运行b。如不成功就a停止再运行b
new Thread(new MyYield(),"a").start();
new Thread(new MyYield(),"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"暂停运行");
}
}
16、管程法
-
可重入锁:ReentrantLock
-
-
public class ThreadYield {
public static void main(String[] args) {
//正常运行,礼让成功就是先运行a,再运行b。如不成功就a停止再运行b
new Thread(new MyYield(),"a").start();
new Thread(new MyYield(),"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"暂停运行");
}
}
17、信号灯法
-
可重入锁:ReentrantLock
-
-
public class ThreadYield {
public static void main(String[] args) {
//正常运行,礼让成功就是先运行a,再运行b。如不成功就a停止再运行b
new Thread(new MyYield(),"a").start();
new Thread(new MyYield(),"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"暂停运行");
}
}
18、线程池
-
频繁的创建和销毁线程耗费较多的CPU资源,并发情况下对运行性能影响较大;
-
所以创建多个线程放入线程池,使用时直接获取,使用完放回池中;
-
提高了响应速度,降低了资源消耗,便于管理线程,
-
corePoolSize:核心池大小
-
maximumPoolSize:最大线程数
-
keepAliveTime:线程没有任务时最多保持多长时间会终止
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
//创建服务,创建线程池
//newFixedThreadPool(10),参数为线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//线程池启动线程
service.execute(new MyThreads());
service.execute(new MyThreads());
service.execute(new MyThreads());
service.execute(new MyThreads());
service.shutdown();
}
}
class MyThreads implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始运行");
}
}
浙公网安备 33010602011771号