同步:排队执行,效率低但是安全
异步:同时执行,效率高但是数据不安全
并发与并行并发:指两个或多个事件在同一个时间段
并行:之两个或多个事件在同一时刻发生
并发是同一个时间段,并行是同一时刻
继承Thread
public void run() {
//这里的代码 就是一条新的执行路径
//这个执行路径的触发方式,不是调用run方法,而是通过thread对象的start()来启动任务
for (int i = 0; i < 10; i++) {
System.out.println("哈哈"+i);
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 10; i++) {
System.out.println("呜呜"+i);
}
}
子线程所调用的方法都在子线程中运行
实现Runnable多线程技术
实现Runnable与集成Thread相比有如下优势:
- 通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况.
- 可以避免单继承所带来的局限性
- 人物与线程本身是分离的,提高了程序的健壮性
- 后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程.
//创建一个任务对象 MyRunnable s = new MyRunnable(); //创建一个线程,并为其分配一个任务 Thread thread = new Thread(s); //执行这个任务 thread.start();
设置和获取线程名称
System.out.println(Thread.currentThread().getName());
new Thread(new myRunnable(),"哈哈").start();
new Thread(new myRunnable()).start();
static class myRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());//currentThread返回对当前正在执行的线程对象的引用
}
}
线程休眠sleep
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
System.out.println(i);
Thread.sleep(1000);
}
}
线程阻塞
线程的中断
一个线程是一个独立的执行路径,他是否应该结束,应该由其自身决定
myRunnable myRunnable = new myRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
for (int i = 0; i < 5; i++) {
System.out.println( Thread.currentThread().getName()+""+i);
}
thread.interrupt();//中断标记
}
static class myRunnable implements Runnable{
@Override
public void run() {
//currentThread返回对当前正在执行的线程对象的引用
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+""+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("发现中断标记,正在中断.");
return;
}
}
}
}
显示锁Lock
Lock l = new ReentrantLock();
l.lock();
l.unlock();
公平锁和非公平锁公平锁,多个线程会按照申请锁的顺序去获得锁,先列队进行排序,顺序进行
优点: 所有线程都会得到资源,不会饿死在队列中
缺点: 吞吐量会下降很多,队列里面出好了第一个线程,其他的线程都会阻塞.cpu唤醒阻塞线程的开销会很大
非公平锁,多个线程去获取锁的时候,会直接尝试获取,获取不到,再去进入等待队列
优点: 可以减少cpu唤醒线程的开销,整体的吞吐效率会高点,CPU也不必唤醒所有进程,会减少唤起线程的数量
缺点: 可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死
缓存线程池长度无限制
任务加入后的执行流程:
1.判断线程池是否存在空闲线程
2.存在则使用
3.不存在,则创建线程并放入线程池,然后使用
public static void main(String[] args) {
//想线程池中加入新的任务
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"拿什么偷懒啊?!");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"拿什么偷懒啊?!");
}
});service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"拿什么偷懒啊?!");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
定长线程池
长度限制
任务加入后的执行流程:
1.判断线程池是否存在空闲线程
2.存在则使用
3.不存在空闲线程池,线程池未满的情况下,则创建线程并放入线程池.
线程池已满的情况下,等待线程池存在空闲线程
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"要努力学习啊!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"要努力学习啊!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"要努力学习啊!");
}
});
}
单线程线程池
周期任务定长线程池
执行流程
1.判断线程池是否存在空闲线程
2.存在则使用
3.不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
周期性任务执行时:
定时执行,当某个时机触发时, 自动执行某任务.
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
}
},5,1,TimeUnit.SECONDS);
}



