1、每个线程都会创建自己的栈空间,运行自己的run方法。
线程的两种创建方法:
①如果是重写Thread的run方法,因为使用的自己独有的资源空间,不存在线程同步的问题(没有实现资源共享)。
②如果是多个Thread使用同一个Runnable对象,因为Runnable是一个共享的资源。多个线程要进行访问共享的数据的时候就需要线程同步的技术,否则就会出现数据不同步,也就是线程不安全(可以实现共享资源)。
2、线程同步
线程安全问题都是由全局变量及静态变量引起的。若每个线程对全局变量、静态变量只有读操作,而无写操作,那么这个全局变量是线程安全的。若多个线程同时执行写操作,一般需要考虑线程同步,否则影响线程安全。
数据同步的三个方法:
①同步代码块
格式:锁的对象可以是任意类型,多个线程对象要使用同一把锁。
Object lock=new Object();
synchronized(lock){
........
}
②同步方法
格式:
public synchronized void method{
....
}
③锁机制(Lock锁,比同步方法和同步代码块功能更强大)
格式:
Lock lock = new ReentrantLock();
lock.lock();
...
lock.unlock();
例子:
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
private static class MyRunnable implements Runnable {
private int ticket = 100;
Object lockObj = new Object();
Lock lock = new ReentrantLock();
@Override
public void run() {
/**
//窗口一直开着,但是对于票操作要进行线程安全控制
while (true) {
synchronized (lockObj) { // ①同步代码块,可以指定任意类型的锁对象
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("==="+name+" "+(ticket--));
}
}
}
*/
// sellTicket();
while (true) {
lock.lock(); // ③Lock锁
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("==="+name+" "+(ticket--));
}
lock.unlock();
}
}
private synchronized void sellTicket(){//当前的锁对象就是this
//窗口一直开着,但是对于票操作要进行线程安全控制
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("==="+name+" "+(ticket--));
}
}
}
}
3、sleep和wait
①Thread.sleep(100);//不会释放锁资源,直到waittingtime到达后继续执行线程体。
②Object.wait()方法,主要用于线程协作的情况,他会释放锁资源。
注意:wait()和notify()必须由同一个锁对象调用,对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait()方法后的线程。wait()和notify()必须在同步代码块或者同步函数中使用。因为必须通过锁对象调用者2个方法。
当多个线程协作时,比如A、B线程,如果A线程在Runnable(可运行)状态中调用了wait()方法,那么A线程就进入了waiting(无限等待)状态,同时失去了同步锁。假如这个时候B线程获取到了同步锁,在运行状态中调用了notify()方法,那么就会将无限等待的A线程唤醒,如果A获得锁对象,那么A线程就会进入Runnable状态,如果没有获得锁对象,那么就进入到Blocked(锁阻塞状态)。

例如:
private static Object obj = new Object();
private static Thread thread1 = new Thread() {
@Override
public void run() {
super.run();
while (true) {
synchronized (obj) { // ①同步代码块,可以指定任意类型的锁对象
try {
obj.wait();//需要notify notifyAll进行唤醒
// obj.wait(50); //自动唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("===" + name);
}
}
}
};
private static Thread thread2 = new Thread() {
@Override
public void run() {
super.run();
while (true) {
synchronized (obj) {
String name = Thread.currentThread().getName();
try {
System.out.println("===" + name + " 获取到锁对象,notify thread1");
obj.notify();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
};