大家好,我是忘鱼。这期干货满满,多线程从浅到深的讲解。
目录
1,Thread.currentThread().getName();
一、多线程的三种建立方式。
//建立多线程方法1
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t=new Mythread();
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程执行了"+i);
}
}
static class Mythread extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程执行了"+i);
}
}
}
}
//建立方式二,
public class ThreadDemo2 {
public static void main(String[] args) {
Runnable th=new MyRunnable();
Thread t=new Thread(th);
t.start();
Runnable th2=new MyRunnable();
Thread t2=new Thread(th2);
t2.start();
// 两个线程近似看做同时执行。
for (int i = 0; i < 5; i++) {
System.out.println("主线程执行了"+i);
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"子线程执行了"+i+"---------"+System.nanoTime());
}
}
}
}
//还是方式2,多了匿名类部类。
//建立多线程方法2匿名类部类
public class ThreadDemo02 {
public static void main(String[] args) {
Runnable th=new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程执行了"+i);
}
}
};
Thread t=new Thread(th);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程执行了"+i);
}
}
}
//建立方式3,算个例题吧
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo3 {
public static void main(String[] args) {
Callable<String> call=new MyCallable(100);
FutureTask<String> task = new FutureTask<>(call);
Thread t = new Thread(task);
t.start();
Callable<String> call2=new MyCallable(200);
FutureTask<String> task2 = new FutureTask<>(call2);
Thread t2 = new Thread(task2);
t2.start();
//两个子线程同时执行,主线程
try {
String t1=task.get();
System.out.println("第一个线程结果"+t1);
} catch (Exception e) {
e.printStackTrace();
}
try {
String t12=task2.get();
System.out.println("第二个线程结果"+t12);
} catch (Exception e) {
e.printStackTrace();
}
}
static class MyCallable implements Callable<String>{
private int n;
public MyCallable (int n) {
this.n = n;
}
int sum=0;
@Override
public String call() throws Exception {
for (int i = 1; i <=n ; i++) {
sum+=i;
}
return "子线程执行结果"+sum;
}
}
}
二、Thread常用方法。
1,Thread.currentThread().getName();
获取当前线程名字,与那个获取当前对象this道理一样。
2,Thread.sleep();
执行到此处休眠,括号内是毫秒。
三、线程安全问题,原因与解决方案。
1、模拟线程安全问题案例:取款。
2、解决方案:三种,同步代码块,同步方法,同步锁。
案例、线程出现安全问题,是由于多个线程同时处理同一资源,导致出错如:给个案例谈谈。比如说小兰与小花共同有一个账户,里面有10万元,她们同时取钱出现了小兰与小花都取了10万,卡里所剩-10万。
当然解决方案有三种,代码块里面会显示。看代码
public class ThreadDemo {
public static void main(String[] args) {
Account acc=new Account("1298323",100000.0);
new DrawThread(acc,"小兰").start();
new DrawThread(acc,"小花").start();
}
}
public class DrawThread extends Thread{
private Account acc;
public DrawThread(Account acc,String name){
super(name);
this.acc=acc;
}
@Override
public void run() {
// 取钱方法
acc.drawMoney(100000);
}
}
import javax.sound.sampled.Line;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
private String cardid;
private double money;
private final Lock lock=new ReentrantLock();
public Account() {
}
public void drawMoney(double money) {
String name=Thread.currentThread().getName();
if(this.money>=money){
System.out.println("恭喜"+name+"取走了钱:"+money);
this.money-=money;
System.out.println("所剩余额:"+this.money);
}else {
System.out.println("余额不足");
}
}
//解决方案一
/*public void drawMoney(double money) {
String name=Thread.currentThread().getName();
synchronized (this) {
if(this.money>=money){
System.out.println("恭喜"+name+"取走了钱:"+money);
this.money-=money;
System.out.println("所剩余额:"+this.money);
}else {
System.out.println("余额不足");
}
}
}*/
// 解决方案2
/*public synchronized void drawMoney(double money) {
String name=Thread.currentThread().getName();
if(this.money>=money){
System.out.println("恭喜"+name+"取走了钱:"+money);
this.money-=money;
System.out.println("所剩余额:"+this.money);
}else {
System.out.println("余额不足");
}
}
*/
// 解决方案3
/*public void drawMoney(double money) {
String name=Thread.currentThread().getName();
lock.lock();
try {
if(this.money>=money){
System.out.println("恭喜"+name+"取走了钱:"+money);
this.money-=money;
System.out.println("所剩余额:"+this.money);
}else {
System.out.println("余额不足");
}
} finally { lock.unlock();
}
}
*/
public Account(String cardid, double money) {
this.cardid = cardid;
this.money = money;
}
public String getCardid() {
return cardid;
}
public void setCardid(String cardid) {
this.cardid = cardid;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
四、线程池(很重要的知识)
1,创建线程池
方法一:ExecutorServive
使用ExecutorServive的实现类ThreadPoolExecutor自创建一个线程池对象,看代码
ExecutorService pool=new ThreadPoolExecutor(3,5,6,
TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
ThreadPoolExecutor里面的一些变量分别是,核心线程,最大线程,临时线程最大存活时间,时间单位,指定任务队列最大数,指定线程工厂默认的就行,这过参数有4种选择看需求。
方法二:Executors
使用Executors(线程池工具类)调用方法创建对象。
这个容易出现bug,不推荐,阿里巴巴java,也是不推荐的。
五、线程池处理Runnable与Callable任务。
1,简单的案例处理
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"hello"+i);
}
}
}
import java.util.concurrent.*;
/*int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler*/
public class ThreadPool {
public static void main(String[] args) {
ExecutorService pool=new ThreadPoolExecutor(3,5,6,
TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
Runnable t=new MyRunnable();
pool.execute(t);
pool.execute(t);
pool.execute(t);
pool.execute(t);
pool.execute(t);
}
}
Callable与Runnable处理基本一样,不过Callable多了个可以调用get方法取值,与上面创建线程第三种那get用法基本一致。
六、定时器
1、Timer实现
直接创建对象,写就完了,这种问题容易出现,不推荐,推荐第二种。
Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("www");
}
},0,2000);
2、scheduledExecutorService实现
ScheduledExecutorService s=new ScheduledThreadPoolExecutor(3);
s.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ "定时输出:aiiaiiaiai"+new Date()+System.currentTimeMillis());
}
},0,2, TimeUnit.SECONDS);
这种创建定时器比较好,就用这。
七、多线程并发并行,与生命周期。
1、并发就是。
线程在间隔极短的时间执行了,看做是同时执行,我算了算大概到纳米级才会出现,时间差异。毫秒级都是看做同时执行的,很夸张了。
2、并行就是。
线程在同一时刻同时执行,不存在时间差的。
3、生命周期
就是线程的生命周期官方提供了6种。
八,总结
加油努力,相信自己。