同步锁
同步与异步
同步:体现了排队的效果,同一时刻只能有一个线程独占资源,其他没有权利的线程排队。
坏处就是效率会降低,不过保证了安全。
异步:体现了多线程抢占资源的效果,线程间互相不等待,互相抢占资源。
坏处就是有安全隐患,效率要高一些。
synchronized关键字
语法格式:
synchronized (锁对象){需要同步的代码(也就是可能出现问题的操作共享数据的多条语句);}
前提
- 同步需要两个或者两个以上的线程(单线程无需考虑多线程安全问题)
- 多个线程间必须使用同一个锁
特点
synchronized同步关键字可以用来修饰方法,称为同步方法,使用的锁对象是this
synchronized同步关键字可以用来修饰代码块,称为同步代码块,使用的锁对象可以任意
同步的缺点是会降低程序的执行效率,但我们为了保证线程的安全,有些性能是必须要牺牲的
为了性能,加锁的范围需要控制好
售票案例
Runnable
package cn.tedu.tickets;/*** 解决接口方式售票安全隐患问题*/public class TicketRunnableV2 {public static void main(String[] args) {TicketRV2 t = new TicketRV2();//统一的目标业务对象Thread m1 = new Thread(t,"马钊");//多线程对象Thread m2 = new Thread(t,"雨来");//多线程对象Thread m3 = new Thread(t,"泡泡");//多线程对象Thread m4 = new Thread(t,"赵彪");//多线程对象m1.start();m2.start();m3.start();m4.start();}}class TicketRV2 implements Runnable{int ticket = 100;//定义一个唯一的锁对象Object o =new Object();@Overridepublic void run() {while (true) {/*synchronized (new Object())锁不住,会new多个Object()对象需要定义一个同步代码块,锁对象需要唯一*/synchronized (o) {if (ticket > 0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + ticket--);} else break;}}}}
Thread
package cn.tedu.tickets;/*** 解决继承Thread方式售票安全隐患问题*/public class TicketThreadV2 {public static void main(String[] args) {TicketTV2 t1 = new TicketTV2("1号窗口马钊");TicketTV2 t2 = new TicketTV2("2号窗口桂宏宇");TicketTV2 t3 = new TicketTV2("3号窗口雨来");TicketTV2 t4 = new TicketTV2("4号窗口泡泡");t1.start();t2.start();t3.start();t4.start();}}class TicketTV2 extends Thread{static int ticket = 100;//Object o = new Object();public TicketTV2(String name) {super(name);}@Overridepublic void run() {while (true){synchronized (TicketTV2.class){if (ticket >0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + "=" + ticket--);} else break;}}}}
StringBuffer与StringBuilder
StringBuffer
加了synchronized ,性能相对较低(要排队,同步),安全性高
StringBuilder
去掉了synchronized,性能更高(不排队,异步),存在安全隐患
线程创建其他方式
ExecutorService/Executors
ExecutorService:用来存储线程的池子,把新建线程/启动线程/关闭线程的任务都交给池来管理
execute(Runnable任务对象)把任务丢到线程池
Executors 辅助创建线程池的工具类
newFixedThreadPool(int nThreads)最多n个线程的线程池newCachedThreadPool()足够多的线程,使任务不必等待newSingleThreadExecutor()只有一个线程的线程池
示例
/*创建线程池ExecutorsnewFixedThreadPool(线程数)方法创建指定线程数的线程池线程池类型为:ExecutorService*/ExecutorService pool = Executors.newFixedThreadPool(5);for (int i = 0;i < 5;i++){//使用池对象完成任务,人任务参数为targetpool.execute(target);}
