03-线程(二)

# 1.同步的安全问题

## 1.同步代码块

```java
格式:
synchronized(锁对象){
//同步代码
}
锁对象:它必须是一个引用类型,可以是任何对象。另外:
要保证多个线程要共享“同一个锁对象”。
```

示例:

```java
1).Tickets类:
public class Tickets implements Runnable {
private int tickets = 100;
private ArrayList list = new ArrayList();
@Override
public void run() {

while (true){
//使用同步代码块--让无序的线程到这里排队
synchronized (list) {//当一个线程进入,加锁,其它线程会自动在外面等待
//判断是否有票
if (this.tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
System.out.println(Thread.currentThread().getName() + " 抢走一张票:" + t);
} else {
System.out.println("没票了,结束....");
break;
}
}//当一个线程执行完毕后,会自动释放锁
}
}
}

2).测试类:
public class Demo {
public static void main(String[] args) {
//1.创建一个票对象
Tickets tickets = new Tickets();

//2.创建两个线程,模拟两个窗口
Thread t1 = new Thread(tickets);
Thread t2 = new Thread(tickets);

t1.setName("窗口1");
t2.setName("窗口2");

t1.start();
t2.start();
}
}
```

## 2.同步方法[常用]

```java
格式:
public synchronized int getTicket(){
//同步代码
}
```

示例:

```java
Tickets类:
public class Tickets implements Runnable {
private int tickets = 100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
int t = getTicket();
if (t > 0) {
System.out.println(Thread.currentThread().getName() +
" 获取一张票:" + t);
}else{
System.out.println("没票了");
break;
}
}
}

//同步方法可以有"锁对象"--this
public synchronized int getTicket(){
//判断是否有票
if (this.tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
return t;
} else {
return 0;
}
}
//扩展:
//1.静态方法是否可以被声明为:同步方法?--可以
//静态方法中不能使用:this,和super
//它的默认"锁对象"是本类的Class对象【在反射讲】

public synchronized static void show(){
}

//2.静态方法中是否可以定义同步代码块?--可以
public static void show2(){
synchronized (obj){//静态的成员变量做锁
}
}
}
```

## 3.Lock锁

1. 锁的简介

当多个线程同时操作数据时,会导致数据的冲突。

例如:存钱--同时用微信和支付宝存钱,发生流程的冲突时,执行流程为:

```
1.微信读取账户金额
2.支付宝读取账户金额
3.微信存入=读取的金额+存入的金额
4.支付宝存入=读取的金额+存入的金额
5.最终金额=支付宝存入的金额(发生覆盖)
```

2. 应用场景

如果我们某一个线程在使用完之前,其他线程不能对其修改,就需要对这个线程增加一个线程锁。

3. demo

```java
格式:
Lock l = new 子类对象();
l.lock(); //加锁
try {
// 同步代码
} finally {
l.unlock(); //解锁
}
```

```java
Tickets类:
public class Tickets implements Runnable {
private int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();//加锁
try {
//判断是否有票
if (this.tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
System.out.println(Thread.currentThread().getName() +
" 抢走一张票:" + t);
} else {
System.out.println("没票了,结束....");
break;
}
}finally {
lock.unlock();//解锁
}

}
}
}

```

## 4.死锁

进程A中包含资源A,进程B中包含资源B,A的下一步需要资源B,B的下一步需要资源A,所以它们就互相等待对方占有的资源释放,所以也就产生了一个循环等待死锁。

# 2.Thread

## 1.Thread构造方法

```java
public Thread():分配一个新的线程对象
public Thread(String name):分配一个指定名字的新的线程对象
任何一个线程都有一个默认的线程名:Thread-索引值
可以直接通过Thread的 getName()获取线程名
public Thread(Runnable target):分配一个带有指定目标新的线程对象
public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字.
```

## 2.Thread成员方法

```java
1.public String getName():获取当前线程的名称
public void setName():设置线程名称
2.public void start():导致此线程开始执行:java虚拟机调用此线程的run方法
3.public void run():此线程要执行的任务在此处定义代码.
4.public void void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂定
5.public static Thread currentThread():返回对当前正在执行的线程对象的引用
```

# 3.等待唤醒案例

```java
public class Demo {
private static Object obj = new Object();

public static void main(String[] args) {
new Thread(){
@Override
public void run() {
synchronized (obj) {
for (int i = 0; i < 20; i++) {
System.out.println("i = " + i);
if(i == 10){
try {
System.out.println("开始无限等待...");
obj.wait();
System.out.println("被唤醒了,恢复运行...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}.start();

//让主线程暂停1秒,目的:让上面的线程先进入到等待状态
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

//定义另一个线程,唤醒所有在obj锁上等待的其它线程
new Thread(){
@Override
public void run() {
System.out.println("唤醒线程开始执行...");
synchronized (obj){
//唤醒等待线程
obj.notifyAll();
}
}
}.start();
}
}
```

猜你喜欢

转载自www.cnblogs.com/studylin/p/12551579.html
03-