1,进程, 程序, 线程的概念
进程: ::程序一次 执行过程,程序运行完毕,进程消失
在运行过程中,需要申请资源,操作系统的资源,有操作系统(Windows linux)分配内存.CPU资源 特点: 一个进程,可以由多个执行者同时操作
2.线程
从属于进程,是进程里面的一个执行者,进程包含线程
3.程序
程序=代码 线程和进程都是由程序构造出来的,程序是静态的,线程和进程是动态的概念
动态:执行的生命周期
进程 ,程序, 线程的区别?
========================================================================
一. Java如何创建一个线程?
1)实现Runnable接口 ,实现了run()方法
public class Worker implements Runnable{
private String name ;
public Worker(String name){
this.name =name;
}
public void run(){
System.out.println(this.name +"去工作")
}
}
2)继承Thread超类 , 覆盖重写run方法
例如: 让2个人同时工作。
public class Worker extends Thread{
private String name ;
public Worker(String name){
this.name =name;
}
public void run(){
System.out.println(this.name +"去工作")
}
}
测试类:WorkerTest
public class WorkerTest{
public static void main (String[] args){
System.out.println("两人同时去工作!")
//方式一
Worker worker1 = new Worker("张三");
Worker worker2 = new Worker("李四");
Thread t1= new Thread(worker1);
Thread t2= new Thread(worker2);
t1.start();
t2.start();
//方式二
// Worker worker1 = new Worker("张三");
// Worker worker2 = new Worker("李四");
// worker1.start();
// worker2.start();
System.out.println("两人工作结束!");
}
}
两人同时去工作!
两人工作结束!
张三去工作
李四去工作
几个重要概念:
主线程 , 子线程
区分主线程和子线程: 使用
Thread.currentThread().getName();
注意事项:
启动线程必须调用start()方法,不能调用run()方法
项目中到底是使用继承Thread还是是实现Runnable,依据情况而定.
3.匿名创建线程:
new Runnable(){ public void run(){ } };
=========================================================================
线程调度
cup调度策略: 时间片轮循策略
当有多个任务需要执行的时候,每一个任务都有自己的执行时间,当时间到达之后,cpu会将执行权交给下一个任务,这种任务执行策略称之为:时间轮循策略
上下文切换:cpu不断的轮循执行多个任务
保留现场: cpu将当前任务的执行情况保留下来,以便下一次调度接续执行提供依据
并发: 一个cpu对应多个任务,需要来回上下文切换
并行: 多个cpu对应多个任务 ,一一执行
结论: 多线程编码并不一定效率高。
===========================================================================
线程的生命周期:
线程运行: 获取到cpu资源 代码正常执行
线程阻塞 : 释放cpu资源 代码不继续往下执行
线程阻塞:
1. io阻塞 :
2. sleep阻塞: 阻塞本线程
3. join 阻塞 :阻塞主线程,
join与sleep的区别是什么?
join是阻塞主线程,当其他子线程完成,再执行。
sleep是阻塞本线程, 阻塞当前执行的线程。
4.synchronized
5.wait/notify (线程通信)
=============================================================
CountDownLatch API使用
定义:通过凭条数目控制阻塞唤醒
CountDownLatch latch = new CountDownLath(2);//初始化凭条数目为2
latch.await();//阻塞主线程
latch.countDown();//凭条数目减少, 凭条数目的值等于0就消除阻塞
=======================================================================
线程安全:
当多个线程访问共享变量时,程序运行产生的结果与预期的结果是不一样的,称之为非线程安全
hashMap/arrayList 非线程安全
java的内存模型
出现线程安全的前提
对个线程同时操作公共变量 包括 :成员变量, 静态变量
解决线程安全
1.synchronized 原理
a 对象锁,每个对象都会有锁标识
b.只有获取到锁执行权限的线程才能欧执行里面的代码
当程序执行完毕,后者程序异常终止,对象锁才会被被释放出来
c一个对象只有一把锁
d 隐式锁 只是一个关键字
e.不公平锁 不能确定哪个线程先得到锁
2. synchronized的用法
a. synchronized 修饰类名称
synchronized(Ticket.class){
}
b. synchronized 修饰方法
public synchronized void fun(){ }
c 修饰 this
synchronized(this){ }
d 修饰变量‘
final String Lock="lock"; synchronized(LOCK){ }
3. 利用原子变量
原子性操作: 一个业务的操作的过程,要么成功,要么失败,中间不允许被其他线程掺和进来。
在java里面,有个操作属于原子操作,
a,赋值
b 读取变量的值
i--是否属于原子性操作?
不属于,会执行三步操作。
包装原子数据类型:
AtomicInteger atomic = new AtomicInteger(0);
atomic.incrementAndGet();//增加
atomic.set(0);//初始化为0
atomic.get();//得到结果
4.Lock 原理
a . 显示锁 不只是关键字,有相对应的操作
Lock lock = new ReentrantLock(); lock.lock();//开启锁 lock.unlock();//释放锁
5 .synchronized和Lock的比较
a.synchronized更加方便,会自动释放锁 ,Lock需要手工的去申请锁资源和释放锁资源。
b.lock锁增加了程序的灵活性,可以结合各种if表达式进行控制
c lock的性能要高于synchronized???