Java.Thread(多线程)
线程就是独立的执行路径
在线程运行,即使没有自己创建线程,后台也会有多个线程,如主线程,gc(垃圾回收)线程
main称之为主线程,为程序的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预。
献丑操作时会带来额外的开销,如cpu调度时间,并发控制开销
线程创建
方法一:
1.定义一个类继承Thread接口
2.重写这个接口的run()方法;
3.使用(实例化该方法)
4.方法名.start();启动线程
package com.wc.demo01;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author 线程的实现
* 实现多线程方法1:
* 1.声明一个类,该类继承Thread接口
* 2.重写Thread接口的run方法
* 3.在main函数中实例化这个类,
* 4.类名.start()启动该线程
*/
public class TestThread extends Thread {
private String url;
private String name;
public TestThread(String url, String name) {
this.url = url;
this.name = name;
}
// public void run() {
// for (int i = 0; i < 500; i++) {
// System.out.println("线程输出+" + i);
// }
// }
@Override
public void run() {
WebDownloader wd = new WebDownloader();
wd.downloader(url, name);
System.out.println("ok");
}
public static void main(String[] args) {
Thread tt = new TestThread("https://image.baidu.com/search/detail", "1");
tt.start();
}
}
/**
* @author 外部类
* 进入多线程执行
*/
class WebDownloader {
public void downloader(String url, String filename) {
try {
FileUtils.copyURLToFile(new URL(url), new File(filename));
} catch (IOException e) {
e.printStackTrace();
System.out.println("downloader下载异常");
}
}
}
创建方式2:
1.创建TestThread2继承Runnable接口
2.实现接口中的run()方法
3,实例化当前类
4.创建thread类并传入当前类的实例化
5.调用thread类的start()方法启动线程
示例:
package com.wc.demo01;
/**
* @author 抽象类实现2
* 1.创建类继承Runnable接口
* 2.重写接口中的run()方法
* 3.创建这个类的实现类
* 4.创建一个thread类传入当前类的实现类
* 5.调用thread类的start方法
*/
public class TestThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("多线程操作" + i);
}
}
public static void main(String[] args) {
Runnable tt2 = new TestThread2();
Thread thread = new Thread(tt2);
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("main方法测试");
}
}
}
多线程同时操作一个对象
/**
* @author Administrator
* 引发高并发问题
* 多个用户访问出现用户访问重复
*/
public class TestThread3 implements Runnable {
private Integer containt = 10;
@Override
public void run() {
while (containt > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "几张票" + containt--);
}
}
public static void main(String[] args) {
TestThread3 tt3 = new TestThread3();
new Thread(tt3, "一号").start();
new Thread(tt3, "二号").start();
new Thread(tt3, "三号").start();
}
}
创建三callable
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FA0aQb70-1648128164688)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220318214446687.png)]
线程状态
线程有五大状态
当创建状态的时候是“创建状态”,
当启动线程start()方法就是”就绪状态“,准备启动
当cpu调度该线程的时候就是“运行状态”,
当线程被睡眠是就是”阻塞状态“,该状态具有不确定因素(cpu调用制度随机,所以不确定自己线程的再次运行时间,会有偏差)
当线程结束是就进入”死亡状态“
如何让线程停止
线程停止不建议使用jdk提供的stop方法,应该让线程运行结束自己停止,或者设置一个标识位让系统通知;
package com.wc.utils;
public class Threadstops implements Runnable{
private boolean flag=true;
public void stoprun(){
this.flag=false;
}
@Override
public void run() {
int i=0;
while (flag){
System.out.println("thread----"+i++);
}
}
public static void main(String[] args) {
Threadstops ts = new Threadstops();
new Thread(ts).start();
for (int i = 0; i < 5000; i++) {
if(i==1500){
ts.stoprun();
} System.out.println("main"+i);
}
}
}
线程休眠
线程休眠就是线程进入堵塞状态,该状态结束后需要抢cpu,可能会有延迟,sleep(毫秒值)1秒=1000毫秒;
import java.time.LocalTime;
public class Threadstops implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
LocalTime now = LocalTime.now();
System.out.println(now);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Threadstops threadstops = new Threadstops();
new Thread(threadstops).start();
}
线程礼让
线程礼让就是cpu调动之后离开cpu,但是当前线程任务还没有借宿,需要看cpu调动,礼让可能成功也可能不成功
一下程序可以多运行几次看看结果不同
public class Threadstops implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始");
Thread.yield();//线程礼让
System.out.println(Thread.currentThread().getName()+"线程结束");
}
public static void main(String[] args) {
Threadstops threadstops = new Threadstops();
new Thread(threadstops,"a").start();
new Thread(threadstops,"b").start();
}
}
线程强制执行
线程在运行的时候,使用线程名.join()强制启动线程可以看作为强制插队当该线程执行完成后才会执行其他的线程(让路)
示例:
public class Threadstops implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i+"thread----》");
}
}
public static void main(String[] args) throws InterruptedException {
Threadstops threadstops = new Threadstops();
Thread thread = new Thread(threadstops,"a");
thread.start();
for (int i = 0; i < 500; i++) {
if(i==300){
thread.join();
}
System.out.println("main----->"+i);
}
}
}
观测线程状态 state
线程分为五个状态使用thread.getstate可以获得线程的当前状态:
NEW 尚未启动的线程状态
RUNNABLE 在Java虚拟机中执行线程的状态
BLOCKED 被阻塞时状态
TIMED_WAITING等待另一个线程执行到指定时间的状态
TERMINATED 已退出线程的状态
package com.wc.utils;
/**
* @author Administrator
* 查看线程状态state
*/
public class ThreadState {
public static void main(String[] args) {
Thread thread=new Thread(() ->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("结束");
});//使用lambda表达式创建一个线程
Thread.State state = thread.getState();//获取线程状态
System.out.println(state);
thread.start();//线程启动
state= thread.getState();
System.out.println(state);
while (thread.getState()!=Thread.State.TERMINATED){
state=thread.getState();
System.out.println(state);
}
}
}
线程优先级
线程优先级Thread.Priorty,设计线程优先级,main函数的线程默认优先级是5,优先级最大是10,最小是1
使用线程优先级需要先设置优先级,在启动线程
设置过优先级不一定按照优先级执行
thread.getpriorty获取线程优先级
thread.setpriorty设置线程优先级
示例:
package com.wc.utils;
import com.google.errorprone.annotations.Var;
/**
* @author 线程优先级Priority
*/
public class MyPriority {
public static void main(String[] args) {
Thread thread = new Thread(() ->{
System.out.println(Thread.currentThread().getPriority()+"->>"+Thread.currentThread().getName());
});
System.out.println(Thread.currentThread().getPriority()+"->>"+Thread.currentThread().getName());
Thread thread1 = new Thread(thread);
Thread thread2 = new Thread(thread);
Thread thread3 = new Thread(thread);
Thread thread4 = new Thread(thread);
Thread thread5 = new Thread(thread);
thread1.setPriority(3);
thread2.setPriority(5);
thread3.setPriority(2);
thread4.setPriority(Thread.MAX_PRIORITY);
thread5.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
public static void priorityTest(){
}
}
守护线程daemon
线程守护setdaemon设置该方法为true属性时,他不会影响java虚拟机,当main方法执行结束的时候他就会自动的停止执行
示例:可以看到我们定一个线程,没有设置终止条件,但是我们使用setdaemon方法设置值为true,当main方法执行结束的时候他也会跟着结束,会有延迟,但是不会一直执行。
package com.wc;
/**
* 守护线程
*
* @author Administrator
*/
public class ThreadDaemon {
public static void main(String[] args) {
You you = new You();
God god = new God();
Thread thread = new Thread(god);
thread.setDaemon(true);
new Thread(you).start();
thread.start();
}
}
class You implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("you" + i);
}
}
}
class God implements Runnable {
@Override
public void run() {
int i = 0;
while (true) {
System.out.println("God" + i++);
}
}
}
线程同步机制synchronized
线程同步机制就是给线程中资源争夺的地方上锁,上了锁线程就只能一个一个的使用(队列)
上锁可以给代码块上锁也可以给方法上锁
public 返回值类型 sychronized 方法名(){
//给方法上锁
}
sychroized{
代码块上锁
}
package com.wc;
/**
* 守护线程
*
* @author Administrator
*/
public class ThreadDaemon {
public static void main(String[] args) {
You myaccount = new You(100, "myaccount");
Drawing me = new Drawing(50, myaccount, "12");
Drawing you = new Drawing(100, myaccount, "你的");
new Thread(me, "wde").start();
new Thread(you, "nide").start();
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(myaccount.many);
});
new Thread(thread).start();
}
}
class You {
Integer many;
String name;
public You(Integer many, String name) {
this.many = many;
this.name = name;
}
}
class Drawing extends Thread {
You account;//账户
Integer drawingMany;//取钱
int nowMany;//手里多少钱
public Drawing(Integer drawingMany, You you, String name) {
super(name);
this.drawingMany = drawingMany;
this.account = you;
}
@Override
public void run() {
synchronized (account) {
if (account.many - drawingMany < 0) {
System.out.println(Thread.currentThread().getName() + "钱不够了");
return;
}
account.many = account.many - drawingMany;
nowMany = nowMany + drawingMany;
System.out.println(Thread.currentThread().getName() + "====>" + nowMany + "--" + account.many);
}
}
}
CopyOnWriteArrayList安全的list集合
java.util包下的线程安全的集合,该集合使用线程插入数据,不会发生并非事件
package com.wc;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 守护线程
*
* @author Administrator
*/
public class ThreadDaemon {
public static void main(String[] args) {
CopyOnWriteArrayList<String> strings = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10000; i++) {
String s= String.valueOf(i);
new Thread(()->{strings.add(Thread.currentThread().getName()+s);}).start();
}
new Thread(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(strings.size());
}).start();
}
}
死锁
死锁就是两个线程手里都有资源但是又想获得对方被synchroized锁住的资源就会导致程序不在运行
产生死锁的四个必要条件:
1.互斥条件:一个资源每次只能被一个进程使用。
2.请求与保持条件:一个线程因请求资源而阻塞时,对以获得的资源保持不放,
3.不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;
`package com.wc.utils;
/**
* 死锁
*
* @author Administrator
*/
public class ThreadDaemon {
public static void main(String[] args) {
UpTest upTest = new UpTest(0);
UpTest upTest1 = new UpTest(1);
new Thread(upTest,"0").start();
new Thread(upTest1,"1").start();
}
}
class ObjOne{
//leiyi
}
class ObjTwo{
//leier
}
class UpTest implements Runnable{
private static ObjOne objOne=new ObjOne();
private static ObjTwo objTwo=new ObjTwo();
Integer choise;
UpTest(Integer choise){
this.choise=choise;
}
public void upTest(){
if(this.choise==0){
System.out.println(Thread.currentThread().getName()+"getone");
synchronized (objOne){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (objTwo){
System.out.println(Thread.currentThread().getName()+"gettwo");
}
}
}
else{
synchronized (objTwo){
System.out.println(Thread.currentThread().getName()+"gettwo");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (objOne) {
System.out.println(Thread.currentThread().getName() + "getone");
}
}
}
}
@Override
public void run() {
upTest();
}
}
`
Lock锁
lock锁是一个可见的锁
lock锁定义:
ReentrantLock lock=new ReentrantLock();//定义一个lock锁
lock.lock();//上锁
lock.unlock();//解锁
package com.wc.utils;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void main(String[] args) {
UpTests upTests = new UpTests();
new Thread(upTests, "1").start();
new Thread(upTests, "2").start();
new Thread(upTests, "3").start();
}
}
class UpTests implements Runnable {
private Integer i = 10;//票数
private final ReentrantLock lock = new ReentrantLock();
@Override
/**
*模拟买票
*/
public void run() {
while (true) {
try {
lock.lock();//加锁
if (i > 0) {
System.out.println(Thread.currentThread().getName() + "zhang" + i--);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
} finally {
lock.unlock();//解锁
}
}
}
}
线程协作
管程法自己没有弄懂,有没有大佬求教
信号灯法
线程池
package com.wc.utils;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class RandomAccess {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个核心线程是5最大线程是10等待回收时间60s队列长度是100的一个线程池
ExecutorService service = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
Future<?> submit = service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
Object o = submit.get();
System.out.println(o);
service.shutdown();
}
}
程是5最大线程是10等待回收时间60s队列长度是100的一个线程池
ExecutorService service = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
Future<?> submit = service.submit(new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}));
Object o = submit.get();
System.out.println(o);
service.shutdown();
}
}