注意:锁一般放在数据容器内
1,方法一:同步代码块:
1,格式:synchronized
synchronized (要锁的对象){操作共享数据的代码;}
2,作用:
3,原理:
每次只能一个线程获取锁进入,执行完毕以后自动解锁,其他线程才可以进来执行。
4,锁对象的要求:
原则上:锁对象必须是同一个对象。
语法上:任意对象都可以作为锁。
5,使用范例:(实际,就是给代码块内的代码加锁)
没锁的线程是无法执行代码块内的代码的;只有上锁被标记的线程才能进入;
//Window类:public class Window extends Thread {//设置共享的变量private static int tickerNumber = 100;***************************************************//一般开发中会专门使用一个对象作为锁;//并且要定义为共享对象;//创建锁对象private static Object obj = new Object();//设置线程名称,并指向父类Thread的对应构造器;public Window(String name) {super(name);}@Overridepublic void run() {while (true) {******************************************//使用同步代码块,锁住对象;解决线程安全问题//注意不要把循环锁上,不然只执行一个对象;synchronized (obj) {if (tickerNumber > 0) {try {Thread.sleep(100);}//捕获sleep异常,这里的代码不需要异常处理代码catch (InterruptedException e) {}tickerNumber--;System.out.println(getName() + "剩余:" + tickerNumber);} else {break;}}//让带锁的对象,休眠一会,避免一个线程对象一直抢锁;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}//main方法类:public class Text06 {public static void main(String[] args) {//创建对象时进行设置线程名称:Window window1 = new Window("window1");Window window2 = new Window("window2");Window window3 = new Window("window3");//以线程对象启动对应线程window1.start();window2.start();window3.start();}}
2,方式二:同步方法:
1,格式:synchronized void
//普通方法:(实例方法)//使用this作为锁;public synchronized void 方法名() {// 操作共享资源的代码}//静态方法://使用 类名.class 作为锁;public static synchronized void 方法名() {// 操作共享资源的代码}
2,作用:
3,原理:(同同步代码块)
每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
4,底层原理:
1. 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法。1. 如果方法是**实例方法**:同步方法默认用**this**作为的锁对象。1. 如果方法是**静态方法**:同步方法默认用**类名.class**作为的锁对象。
5,使用范例:
//Window类:public class Window extends Thread {private static int tickNumbers = 100;public Window(String name) {super(name);}@Overridepublic void run() {//循环卖票:while (true) {//调用同步方法;(静态的)sales();//设置线程对象的延迟值,避免一个对象一直抢锁;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if (tickNumbers == 0) {break;}}}public static synchronized void sales() {// System.out.println(Window.class);//静态对象使用 类名.class 作为对象;if (tickNumbers > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {}tickNumbers--;//注意:这里的获取线程名称要先获取当前线程对象,因为是静态的,会有多个线程对象,如不先获得,系统无法识别出线程名System.out.println(Thread.currentThread().getName() + "\t剩余:" + tickNumbers);}}}//main方法类:public class Text07 {public static void main(String[] args) {//创建线程对象并设置线程名;Window window1 = new Window("window1");Window window2 = new Window("window2");Window window3 = new Window("window3");window1.start();window2.start();window3.start();}}
3,方式三:Lock锁:
1,Lock的API :ReentrantLock()
2,Lock的介绍:
1. u为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,更加灵活、方便。1. Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作。1. Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象。
3,格式:(lock)
lock.lock();try {操作共享资源代码} finally {lock.unlock();}
4,使用范例:
//main:public class Text01 {public static void main(String[] args) {MyLock myLock1 = new MyLock();MyLock myLock2 = new MyLock();myLock1.start();myLock2.start();}}//mylock类:public class MyLock extends Thread{//创建lockprivate static Lock lock=new ReentrantLock();@Overridepublic void run() {try {//获得锁:lock.lock();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}} catch (Exception e) {e.printStackTrace();} finally {//释放锁://记得在finally里面释放,否则进程一直被一个线程对象拿着锁执行;lock.unlock();}}}

