/**
* 今天呢特意抽时间来随笔一番线程相关的小Demo;
* 下面先开始关于线程同步的小Demo;
* 这段随笔可能不会太精炼,故而读者有兴趣之余可能需要耗一点时间来磨;
* 后面有时间精力我会其进行简练概要;
*/
package cn.thread;
/**
* 定义一个自己的线程类; 通过实现Runnable接口来实现;
* 来测试线程同步相关的问题;
* 首先说明一下线程同步的几种形式:
* 1. 同步方法;
* 2. 同步代码块;
* 3. 同步锁;
* @author TANJIYUAN
*/
public class ClassThreadTest implements Runnable {
/**
* 还是前两天线程Demo的套路;
* 简单写一个Demo来说明同步的与常运行的区别;
* 首先创建一个静态int类型的常量;
*/
private static int MONEY = 6;
/**
* 重写run()方法;
* 内置要执行的代码;
*/
public void run() {
for(int i=0; i<MONEY; i++){
if (MONEY > 0) {
goon();
}
}
}
/**
* 接下来把要同步的代码封装到一个具体的方法中;
* 首先不要管下面注释掉的synchronized,后面我会说到它的作用和用在此处的意义;
* 如果以常运行的方式执行这段代码,将会出现线程示例AAA,BBB,CCC有几率同时抢到一样的金额;
* 而我在当前Demo中MONEY常量的用意是准备分发不同线程,分别抢机会,每人都抢,但不能两人或两人以上抢重复;
* 那么问题来了,如何实现呢?
* 下面就是被注释掉的synchronized关键字出场的时刻了;
* 它被我放在这里,说明两件事:
* 1. 它可以在这里存在(它可以用来修饰方法);
* 2. 它可以解决我刚刚提到的同步问题;
* 好,说到这里;就来详细的说一下synchronized关键字的用法以及规则;
* synchronized同步关键字,他能够用来同步
* 1. 代码块;
* 2. 方法;
* 像刚刚我们下面我们用到的这种方式就是同步方法的场景;
* 好,如果测试过,就会发现当发开synchronized关键字后,每个线程对象获取到的MONEY都是唯一的;
* 没有另一个线程对象抢占和另一个线程对象同样的MONEY;
* ok,以上是关于synchronized关键修饰方法的解读;
* 后面会有其他场景的介绍与分析;
*/
public static /*synchronized*/ void goon() {
try {
// 线程类的等待机制;参数为毫秒级别;
Thread.sleep(100);
} catch (InterruptedException e) {
// 控制台打印异常详细信息;
e.printStackTrace();
}
/**
* 获取当前线程名称;
* MONEY--数据运算操作;
*/
System.out.println(Thread.currentThread().getName() + ": " + MONEY--);
}
}
/**
* 创建临时的测试类;
* @author TANJIYUAN
*/
class Test {
// 程序的主函数|入口
public static void main(String[] args) {
// 实例化自己的线程类;
ClassThreadTest myRunnable = new ClassThreadTest();
/**
* 实例化多个Thread线程对象;
* 指定Runnable对象;
*/
Thread a = new Thread(myRunnable, "AAA");
Thread b = new Thread(myRunnable, "BBB");
Thread c = new Thread(myRunnable, "CCC");
// 线程启动;
a.start();
b.start();
c.start();
}
}
package cn.thread;
/**
* 下面这段是描述synchronized同步代码块的说明;
* 其语法格式为: synchronized(同步锁){}|synchronized{};
* @author TANJIYUAN
*
*/
public class ClassThreadTest implements Runnable {
// 首先创建一个静态int类型的常量;
private static int MONEY = 6;
/**
* 初始化一个对象锁;
* 这里的对象锁可以是任意类型,在使用的时候需要注意,多线程需要使用同一把锁;
*
* 你可以把他理解成一个标识;
*
*/
Object lock = new Object();
/**
* 这里是对应实现的run()方法;
*/
public void run() {
for(int i=0; i<MONEY; i++){
/**
* 同步代码块;
* 在此处设置同步所达到的效果和先前同步方法的效果一样;
*/
synchronized(lock) {
if (MONEY > 0) {
goon();
}
}
}
}
public static /*synchronized*/ void goon() {
try {
// 线程类的等待机制;参数为毫秒级别;
Thread.sleep(100);
} catch (InterruptedException e) {
// 控制台打印异常详细信息;
e.printStackTrace();
}
/**
* 获取当前线程名称;
* MONEY--数据运算操作;
*/
System.out.println(Thread.currentThread().getName() + ": " + MONEY--);
}
}
/**
* 创建临时的测试类;
* @author TANJIYUAN
*/
class Test {
// 程序的主函数|入口
public static void main(String[] args) {
// 实例化自己的线程类;
ClassThreadTest myRunnable = new ClassThreadTest();
/**
* 实例化多个Thread线程对象;
* 指定Runnable对象;
*/
Thread a = new Thread(myRunnable, "AAA");
Thread b = new Thread(myRunnable, "BBB");
Thread c = new Thread(myRunnable, "CCC");
// 线程启动;
a.start();
b.start();
c.start();
}
}
package cn.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 下面来说一下比synchronized同步更高级的一种同步方式;
* 同步锁;
* 常用方法:
* 1. 加锁: public void lock();
* 2. 释放锁: public void unlock();
* 下面我们来看一下加了同步锁之后的同步效果;
*
*
* 首先,还是先创建一个自己的线程实现类;
* @author Administrator
*/
public class MyThreadLock implements Runnable {
/**
* 还是和上面的Demo采用一样的示例;
* 首先初始化创建一个静态的常量MONEY;
*/
private static int MONEY = 6;
/**
* 然后在这里实例化创建一个同步锁;
* Lock本身是一个接口,故而不能够直接实例化自己的实例;
* 于是只能通过自身的实现来实例后指向自己;
* 当然同步锁对象的创建位置你可以根据自己程序的优化结构动态实例化;
*/
Lock lock = new ReentrantLock();
/**
* 下面是实现线程的执行函数run()方法;
*/
public void run() {
/**
* 继续开一个循环事物,来保证线程的持续性;
*/
for(int i=0; i<6; i++) {
/**
* 加同步锁;
* 之所以选择这块代码添加锁机制,是因为多个线程会同时访问这段代码进行数据操作;
* 也可以说这段代码具有共享性;
*/
lock.lock();
if(MONEY>0){
goon();
}
/**
* lock锁在开启后是需要手动关闭的;
* 在此处通过实例化的lock对象进行锁关闭;
* (说明一下哦,如果忘记关闭lock锁,或有死锁异常哦;)
*/
lock.unlock();
}
}
/**
* 封装操作动作成成员方法;
*/
public static void goon() {
// 获取当前执行线程的名称;
System.out.println(Thread.currentThread().getName()+ ": " + MONEY--);
}
}
/**
* 创建自己的临时测试类;
* @author Administrator
*/
class Test {
/**
* 程序主函数|入口;
* @param args
*/
public static void main(String[] args) {
/**
* 实例化自己的线程类;
*/
MyThreadLock mt = new MyThreadLock();
/**
* 实例化Thread线程类,指定自己的实现类线程类;
* 通过构造进行初始化;
*/
Thread a = new Thread(mt,"AAA");
Thread b = new Thread(mt,"BBB");
Thread c = new Thread(mt,"CCC");
/**
* 启动线程;
*/
a.start();
b.start();
c.start();
/**
* 在最后再说一下关于线程的生命周期:
* 一般主要分这几个阶段:
* 1. 新建状态;
* 2. 就绪状态(可随时执行);
* 3. 阻塞状态(等待状态);
* 4. 执行状态;
* 5. 结束线程;
*/
}
}