多线程与并发
多线程
线程的实现方法
继承Thread类
- 继承Thread类
- 重写run方法
- start开启线程
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->haha");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("thread1");
myThread.start();
}
}
实现Runnable接口
- 实现Runnable接口
- 创建Thread对象
- 参数为实现类
- start启动线程
public class MyThread2 implements Runnable {
@Override
public void run() {
System.out.println("hahaha");
}
public static void main(String[] args) {
new Thread(new MyThread2()).start();
}
}
实现Callable接口
//1. 实现Callable,返回值类型为String
public class Thread3 implements Callable<String> {
@Override
// 2. 重写call方法
public String call() throws Exception {
System.out.println("hahahah");
return "我是返回值";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3. 打开服务,参数为服务个数
ExecutorService service = Executors.newFixedThreadPool(1);
//4. 提交执行
Future<String> future = service.submit(new Thread3());
//5. 获取返回值
String s = future.get();
//6. 结束服务
service.shutdownNow();
}
}
静态代理模式
案例:
public class StaticProxy {
//************测试主方法*************
public static void main(String[] args) {
You you = new You();
WeddingCompany weddingCompany = new WeddingCompany(you);
weddingCompany.marry();
}
}
//*************************
//结婚接口
interface Marry {
//结婚方法
void marry();
}
//*************************
//真实对象实现结婚接口
class You implements Marry {
//重写结婚方法
@Override
public void marry() {
System.out.println("要结婚了,哈哈哈");
}
}
//*************************
//代理对象实现结婚接口
class WeddingCompany implements Marry {
private Marry target;
//通过传入参数的方式调用真实对象
public WeddingCompany(Marry target) {
this.target = target;
}
//重写结婚方法
@Override
public void marry() {
before();
this.target.marry();
after();
}
private void after() {
System.out.println("收尾款");
}
private void before() {
System.out.println("布置现场");
}
}
核心点:
直接使用代理对象即可,为什么代理对象可以拥有真实对象的方法,因为new代理对象时,传参传了个真实对象!!
线程状态

停止线程
- 不推荐使用JDK提供的stop() destory()废弃方法。
- 可以使用flag=false让线程停止
public class Thread4 implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i=0;
while (flag) {
System.out.println("thread4...."+i++);
}
}
public void myStop() {
this.flag = false;
}
//测试类
static class Test{
public static void main(String[] args) {
Thread4 thread4 = new Thread4();
new Thread(thread4).start();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
if (i==800){
thread4.myStop();
}
}
}
}
}
线程休眠sleep(抱着锁睡觉)
sleep不释放锁,其他线程必须等待它执行完毕才能执行
public class ThreadDemo {
//lock对象将传入synchronized代码块里,为保证两个线程抢一把锁
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (lock){
try {
System.out.println("A休眠10秒不放弃锁");
Thread.sleep(10000);
System.out.println("A休眠10秒醒来");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
synchronized (lock){
System.out.println("B休眠10秒不放弃锁");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B休眠10秒醒来");
}
}).start();
}
}
A休眠10秒不放弃锁
A休眠10秒醒来
B休眠10秒不放弃锁
B休眠10秒醒来
或者
B休眠10秒不放弃锁
B休眠10秒醒来
A休眠10秒不放弃锁
A休眠10秒醒来
线程礼让yield
public static void main(String[] args) {
new Thread(() -> {
System.out.println("A在执行。。。");
Thread.yield();
System.out.println("A结束了");
}).start();
new Thread(() -> {
System.out.println("B在执行");
Thread.yield();
System.out.println("B结束了");
}).start();
}
A在执行
A结束了
B在执行
B结束了
或者
A在执行
B在执行
A结束了
B结束了
线程插队join
**注意 **:谁调用让谁插队
public static void main(String[] args) {
Thread threadA=new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("A在执行==》"+i);
if (i==50){
}
}
});
threadA.start();
Thread threadB=new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("B在执行==》"+i);
if (i==50){
try {
// 让A线程插队
threadA.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
threadB.start();
}
线程状态以及优先级
thread.getState()
thread.setPriority(int requestedPriority)
thread.getPriority();
守护线程
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。
Thread daemonTread = new Thread();
// 设定 daemonThread 为 守护线程,default false(非守护线程)
daemonThread.setDaemon(true);
// 验证当前线程是否为守护线程,返回 true 则为守护线程
daemonThread.isDaemon();
并发
并发:同一个对象被多个线程同时操作
synchronized
修饰方法
public class synTest {
public static void main(String[] args) {
DemoService service = new DemoService();
TestThread testThread = new TestThread(service);
new Thread(testThread,"线程1:").start();
new Thread(testThread,"线程2:").start();
}
}
class DemoService {
synchronized public void foo1() {
System.out.println(Thread.currentThread().getName() + "foo1开始了。。。。");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "foo1结束了。。。。。");
}
synchronized public void foo2() {
System.out.println(Thread.currentThread().getName() + "foo2开始了。。。。");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "foo2结束了。。。。。");
}
}
class TestThread implements Runnable {
private DemoService demoService;
public TestThread(DemoService demoService) {
this.demoService = demoService;
}
@Override
public void run() {
demoService.foo1();
demoService.foo2();
}
}
case1:foo1和foo2加锁时输出结果:
线程1:foo1开始了。。。。
线程1:foo1结束了。。。。。
线程1:foo2开始了。。。。
线程1:foo2结束了。。。。。
线程2:foo1开始了。。。。
线程2:foo1结束了。。。。。
线程2:foo2开始了。。。。
线程2:foo2结束了。。。。。
case2:foo1和foo2没加锁时输出结果:
线程1:foo1开始了。。。。
线程2:foo1开始了。。。。
线程2:foo1结束了。。。。。
线程2:foo2开始了。。。。
线程1:foo1结束了。。。。。
线程1:foo2开始了。。。。
线程1:foo2结束了。。。。。
线程2:foo2结束了。。。。。
case3:foo1加锁,foo2没解锁时:
线程1:foo1开始了。。。。
线程1:foo1结束了。。。。。
线程1:foo2开始了。。。。
线程2:foo1开始了。。。。
线程2:foo1结束了。。。。。
线程2:foo2开始了。。。。
线程1:foo2结束了。。。。。
线程2:foo2结束了。。。。。
总结:synchronized修饰方法时,锁的是调用此方法的对象,即为this。查看源码可以明白,修饰方法时候默认使用synchronized(this)。case1可以看出,无论线程1还是线程2,执行foo1还是foo2的时候由于对象被锁,所以调用此对象的其他线程无法进入。case2则特地乱套,两个线程随机执行对象方法。case3,由于foo1加锁,所以foo1之前期间不会被有其他线程进入。
同步代码块
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
new Thread(() -> {
synchronized (list) {
list.add(1);
}
}).start();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
Lock
class A{
// 使用Lock的子类ReentrantLock
private final ReentrantLock lock=new ReentrantLock();
public void m(){
lock.lock();
try {
// 代码块
}finally {
lock.unlock();
}
}
}
synchronized和Lock的区别
<img src="../myhexo/source/images/image-20210428105514117.png" alt="image-20210428105514117" style="zoom:80%;" />
线程池

public class Testpool {
public static void main(String[] args) {
//1. 创建服务,创建线程池
//newFixedThreadPool 参数为线程池大小
ExecutorService service= Executors.newFixedThreadPool(10);
// 执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2. 关闭连接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("hahahaha");
}
}