1.线程同步:
锁:保护资源,一把锁只有一把钥匙
只有执行完被锁住的程序块钥匙才能被释放
资源就是卫生间/线程就是等待卫生间/锁就是卫生间的门
加锁的原因:同一个属性可以被不同的对象访问
锁保护的对象:成员属性/静态成员属性
互斥锁的种类:
this:当前对象锁
类.class:当前类的class对象锁
成员属性
方法上加锁:锁就是this对象的锁
静态方法加锁:class实例对象的锁
锁是属于谁:
锁是属于对象的,每一个对象都有一把唯一的锁
锁:每一个对象都有一个锁,而且每一个对象都只有唯一一把钥匙
同步:使用了同一个锁的代码块就叫实现了同步
同步块
同步方法
锁:当前对象锁:synchronized(this)/普通同步方法
类锁(class对象锁):synchronized(类.class)/静态同步方法
私有锁:使用类中一个成员属性作为锁
死锁:相互等待对方占用的资源
示例1:
package thread_2;
public class LockTest {
public static void main(String[] args) {
final Method m = new Method();
Thread t1 = new Thread(new Runnable() {
public void run() {
m.m1();
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
m.m2();
}
});
t1.start();
t2.start();
}
}
class Method{
public void m1(){
synchronized (this) {//this
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public void m2(){
synchronized (this) {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public void m3(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public void m4(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
线程t1执行m1
线程t2执行m2
没加锁时,就是两个线程交互打印
加锁时,都加this锁,t1先启动,拿到钥匙,开始执行,然后t2抢到cpu,但t2没有拿到钥匙,所以把cpu让给t1,t1继续执行,当t1执行完之后,让出钥匙t2开始执行,
示例2:
package thread_2;
public class LockTest_2 {
public static void main(String[] args) {
Method2 m = new Method2();
Thread t1 = new Thread(m);
t1.start();
m.m1("主线程1");
m.m2("主线程2");
}
}
class Method2 implements Runnable{
public int b = 100;
public void run() {
m1("子线程");
}
public synchronized void m1(String name){
System.out.println("m1"+":"+b+":"+name);
}
public synchronized void m2(String name){
b=200;
System.out.println("m2"+":"+b+":"+name);
}
}
运行结果:
m1:100:主线程1
m2:200:主线程2
m1:200:子线程
运行的顺序:start()—–主线程m1—主线程m2—-子线程m1
示例3:
package thread_2;
public class LockTest_2 {
public static void main(String[] args) {
Method2 m = new Method2();
Thread t1 = new Thread(m);
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m.m1("主线程1");
//m.m2("主线程2");
}
}
class Method2 implements Runnable{
public int b = 100;
public void run() {
m1("子线程");
}
public synchronized void m1(String name){
System.out.println(name);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("m1"+":"+b+":"+name);
}
public synchronized void m2(String name){
b=200;
System.out.println("m2"+":"+b+":"+name);
}
}
运行结果:
子线程
m1:100:子线程
主线程1
m1:100:主线程1
子线程的锁是m,主线程的锁也是m,当子线程(t1.start.run m1.m)先拿到了锁之后,就算m1中有sleep,还是会等待时间完之后,子线程执行完,主线程(main m1(m))才开始执行。
示例4:死锁
package thread_2;
public class DeadLockTest {
public static void main(String[] args) {
DeadLock t1 = new DeadLock(0);
DeadLock t2 = new DeadLock(1);
t1.start();
t2.start();
}
}
class DeadLock extends Thread{
private static String lock1 = new String();
private static String lock2 = new String();
private int flag ;
public DeadLock(int flag) {
super();
this.flag = flag;
}
public void run() {
if(flag==0){
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock2) {
}
}
}else{
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock1) {
}
}
}
}
}
理解:线程t1使用了lock1锁,而且在锁定代码块需要lock2锁
线程t2使用了lock2锁,而且在锁定代码块需要lock1锁
t1占据lock1,等到lock2之后,才能释放lock1
t2占据lock2,等到lock1之后,才能释放lock2
2.线程通信
生产者和消费者
资源model类(mantou): id
资源类(resource):资源model的数组 放入方法(pop()),取出方法(push())
消费者类(Consummer):consumer resource.pop run()
生产者类(procedure):procedure resource.push run()
t1,t2 生产
t3,t4 消费
示例1:
package thread_2;
public class ProAndCusTest {
public static void main(String[] args) {
Resurce resurce = new Resurce();
Customer customer = new Customer(resurce);
Producer producer = new Producer(resurce);
Thread t1 = new Thread(customer);
Thread t2 = new Thread(customer);
Thread t3 = new Thread(producer);
Thread t4 = new Thread(producer);
t1.setName("消费者1");
t2.setName("消费者2");
t3.setName("生产者1");
t4.setName("生产者2");
t3.start();
t4.start();
t1.start();
t2.start();
}
}
class Mantou{
int id;
}
class Resurce{
Mantou[] arrMantou = new Mantou[10];
int index = 0;
//放入资源
public synchronized void push(Mantou mantou) throws InterruptedException{
if(index == arrMantou.length){
this.wait();
this.notifyAll();
}else{
arrMantou[index] = mantou;
index++;
System.out.println(Thread.currentThread().getName()+":生产了"+index+"馒头");
}
}
public synchronized Mantou pop() throws InterruptedException{
if(index==0){
this.wait();
this.notifyAll();
}else{
System.out.println(Thread.currentThread().getName()+":消费了"+index+"馒头");
index--;
}
return arrMantou[index];
}
}
//消费者
class Customer implements Runnable{
private Resurce resurce;
public Customer(Resurce resurce) {
super();
this.resurce = resurce;
}
public void run() {
System.out.println("消费者消费产品");
while(true){
try {
resurce.pop();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//生产者
class Producer implements Runnable{
private Resurce resurce;
public Producer(Resurce resurce) {
super();
this.resurce = resurce;
}
public void run() {
System.out.println("生产者生产产品");
while(true){
Mantou mantou = new Mantou();
try {
resurce.push(mantou);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
运行结果:
生产者生产产品
生产者1:生产了1馒头
生产者1:生产了2馒头
生产者1:生产了3馒头
生产者1:生产了4馒头
生产者1:生产了5馒头
生产者1:生产了6馒头
生产者1:生产了7馒头
生产者1:生产了8馒头
生产者1:生产了9馒头
生产者1:生产了10馒头
消费者消费产品
消费者1:消费了10馒头
消费者1:消费了9馒头
消费者1:消费了8馒头
消费者1:消费了7馒头
消费者1:消费了6馒头
消费者1:消费了5馒头
消费者1:消费了4馒头
消费者1:消费了3馒头
消费者1:消费了2馒头
消费者1:消费了1馒头
消费者消费产品
生产者生产产品
生产者2:生产了1馒头
生产者2:生产了2馒头
生产者2:生产了3馒头
生产者2:生产了4馒头
生产者2:生产了5馒头
生产者2:生产了6馒头
生产者2:生产了7馒头
生产者2:生产了8馒头
生产者2:生产了9馒头
生产者2:生产了10馒头
4.线程池
池中有很多存在的线程
平时线程的过程:
启动线程
执行线程
线程回收
有了线程池,启动线程的时间和线程回收的时间都不会用了,只有执行线程任务会需要时间
模拟线程池:
ThreadPool :线程池 List
ThreadTask :执行任务的线程
Task:任务 abstract deal()
TaskQueue:任务队列
excute(Runnable runnable):在未来某一个时间执行给定的命令,该命令可能在新的线程,已入池的线程或者正调用的线程总执行。
AbstractExecutorService:普通线程池
ScheduleExecutorService(interface):实现调度的线程池
excutorService
shutDown:线程池的关闭
executes(class):工具类
得到各种线程池:
newSingleThreadExecutor():得到单个线程
示例1:
package thread_2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();//单个工作的线程的线程池
MyTask task1 = new MyTask();
MyTask task2 = new MyTask();
MyTask task3 = new MyTask();
MyTask task4 = new MyTask();
pool.execute(task1);//任务交给线程池执行
pool.execute(task2);
pool.execute(task3);
pool.execute(task4);
pool.shutdown();//关闭线程池
}
}
运行结果:
pool-1-thread-1执行任务
pool-1-thread-1执行任务
pool-1-thread-1执行任务
pool-1-thread-1执行任务
newFixedThreadPool:固定线程,固定线程数
package thread_2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService pool =Executors.newFixedThreadPool(3);//固定线程,固定线程数
MyTask task1 = new MyTask();
MyTask task2 = new MyTask();
MyTask task3 = new MyTask();
MyTask task4 = new MyTask();
pool.execute(task1);//任务交给线程池执行
pool.execute(task2);
pool.execute(task3);
pool.execute(task4);
pool.shutdown();//关闭线程池
}
}
运行结果:
pool-1-thread-1执行任务
pool-1-thread-1执行任务
pool-1-thread-3执行任务
pool-1-thread-2执行任务
newCachedThreadPool:更具需要创建新县城吃,但是以前构造的线程池可用时会重用。
示例3:
package thread_2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
MyTask task1 = new MyTask();
MyTask task2 = new MyTask();
MyTask task3 = new MyTask();
MyTask task4 = new MyTask();
pool.execute(task1);//任务交给线程池执行
pool.execute(task2);
pool.execute(task3);
pool.execute(task4);
pool.shutdown();//关闭线程池
}
}
运行结果:
pool-1-thread-1执行任务
pool-1-thread-2执行任务
pool-1-thread-4执行任务
pool-1-thread-3执行任务
newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期执行
示例4:
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
/**
* command:任务
* initialDelay:开始时间
* period:
* unit:时间单位
*/
pool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"++++++++");
}
}, 1000, 3000, TimeUnit.MILLISECONDS);
pool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"----------");
}
}, 1000, 3000, TimeUnit.MILLISECONDS);
// pool.scheduleWithFixedDelay(command, initialDelay, delay, unit);
请关注“知了堂学习社区”,地址:http://www.zhiliaotang.com/portal.php