关于线程池的基本操作
线程是一个程序内部的一条执行流程
如果程序中只有一条执行流程,那这个流程就是单线程的程序。
多线程指的是从软硬件上来实现多条执行流程的技术,多条线程由cpu负责调度执行。
1.创建多线程
package d1_creat_thread;
/*
目标:创建一个线程方案一:继承Thread类
*/
public class ThreadTest1 {
//main方法是一条默认的主线程执行的
public static void main(String[] args) {
//3.创建一个MyThread线程类的对象代表一个线程
Thread t=new MyThread();
//4.启动线程
t.start();//自动执行run方法
for (int i = 0; i <=5 ; i++) {
System.out.println("主线程main" + i);
}
}
}
package d1_creat_thread;
/**
* 让子类继承一个Thread类
*/
public class MyThread extends Thread {
//2.重写Thread类的run方法
@Override
public void run() {
//描述线程的执行任务
for (int i = 0; i <=5 ; i++) {
System.out.println("子线程MyThread测试" + i);
}
}
}
多线程的创建方法一如上面所示;
优点:编码简单
缺点:已经继承了Thread类,无法继承其他类,不利于功能的拓展。
注意事项:
启动线程使用的是start方法,不是调用的run方法
不要把主线程任务放在子线程启动之前;
方式二
实现Runnable接口
public class ThreadTest2 {
public static void main(String[] args) {
//3.创建一个任务对象
Runnable target=new MyRunable();
//4.把任务对象交给线程来处理
new Thread(target).start();
for (int i = 0; i <=5 ; i++) {
System.out.println("主线程输出===>" + i);
}
}
}
package d1_creat_thread;
//1.实现接口
public class MyRunable implements Runnable{
//2.重写run方法
@Override
public void run() {
for (int i = 0; i <=5; i++) {
System.out.println("子线程输出===>" + i);
}
}
}
方式二
优点:
任务类只是实现了接口类,没有实现继承类,拓展能力强。
缺点:
需要多一个Runable对象
前两种方法有个最大问题是重写的run方法均不能直接返回结果
方式三
最大的优点:
可以返回线程执行完毕之后的结果
缺点:
编码复杂
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTest3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3.开始创建一个Callable对象
Callable<String>call= new MyCallable(100);
//4.将其封装成一个FutureTask对象
FutureTask<String>f1= new FutureTask<>(call);
//5.把对象交给Thread对象
new Thread(f1).start();
//获取执行完毕返回的结果
String rs=f1.get();
System.out.println(rs);
}
}
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
//描述线程的任务,返回线程执行后的结果
int sum=0;
for (int i = 0; i <=n ; i++) {
sum+=i;
}
return "线程求出了1-"+n+"的值";
}
}
Thread常见方法
public class MyThread extends Thread{
@Override
public void run() {
Thread t=Thread.currentThread();
for (int i = 1; i <=5 ; i++) {
System.out.println(t.getName()+t);
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
Thread t1=new MyThread();
t1.start();
System.out.println(t1.getName());
Thread t2=new MyThread();
t2.start();
System.out.println(t2.getName());
Thread m=Thread.currentThread();
//谁执行上述代码,谁输出线程名称
for (int i = 1; i <=5 ; i++) {
System.out.println("主线程输出" + i);
}
}
}
关于解决线程安全问题有三种方法
1.线程同步思想
import sun.misc.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
public double money;
public String cardld;
private Lock lk= new Lock();
public Account() {
}
public Account(double money, String cardld) {
this.money = money;
this.cardld = cardld;
}
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(name + "取钱后余额剩余" + this.money);
}else {
System.out.println(name + "来取钱,余额不足");
}
}
只能允许一个对象,遵循唯一思想
方法二
同步方法
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(name + "取钱后余额剩余" + this.money);
} else {
System.out.println(name + "来取钱,余额不足");
}
}*/
方法三:
lock锁
public synchronized void drawMoney(double money) throws Exception {
String name = Thread.currentThread().getName();
try {
lk.lock();
if (this.money >= money) {
System.out.println(name + money + "取钱成功");
this.money -= money;
System.out.println(name + "取钱后余额剩余" + this.money);
} else {
System.out.println(name + "来取钱,余额不足");
}
} finally {
lk.unlock();//解锁
}
线程池:
线程池是一个复用线程的技术
1.创建一个线程池
public class ThreadPoolTest1 {
public static void main(String[] args) {
//1.创建一个线程池
/*public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)*/
ExecutorService pool=new ThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
Runnable target=new MyRunnable();
pool.execute(target);//线程池会创建一个新线程,自动处理这个任务,自动执行。
pool.execute(target);
pool.execute(target);
pool.execute(target);//核心线程占满,复用前面的核心线程
pool.execute(target);//核心线程占满,复用前面的核心线程
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//拒绝新任务
pool.execute(target);
pool.shutdown();//等线程池的任务结束执行完毕后,再关闭线程
//pool.shutdownNow();//立即关闭线程池;
}
}
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
//描述线程的任务,返回线程执行后的结果
int sum=0;
for (int i = 0; i <=n ; i++) {
sum+=i;
}
return Thread.currentThread().getName()+"线程求出了1-"+n+"的值"+sum;
}
}
可以使用Callable类来返回未来对象处理的值
关于乐观锁和悲观锁
CAS算法
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnable2 implements Runnable {
//乐观锁
//整数修改的乐观锁,原子类
//CAS算法
private AtomicInteger count=new AtomicInteger();
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName()+"count====>" + count.incrementAndGet());
}
}
}
public class MyRunnable implements Runnable{
//悲观锁
private int count;
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
synchronized (this){
System.out.println("count====>" + (++count));
}
}
}
}