线程
1.多线程原理
主线程在main()方法被调用时创建,当Thread类的对象创建并调用start()方法线程启动,此时主线程和自定义线程同时(交错)运行,整个应用在多线程下运行
栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间
2.Thread类
a).构造方法;
Thread():无参构造方法
Thread(String name):线程名称
Thread(Runnable target):
Thread(Runnablr target,String name):
b)常用方法:
public String getName() :获取当前线程名称。
public void start() :启动线程
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
3.实现Runnable接口创建线程
定义是实现接口的类,创建对象,调用Thread(Runnable target)构造方法创建线程。然后调用start()启动线程
示例:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable");
}
}
调用
public class Runnable接口创建线程 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable);
t.start();
}
}
tips:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
4.Thread和Runnable的区别
1.第一种方式需要子类继承自Thread。由于Java是“单继承”,所以对子类造成了不方便。
2.第二种方式需要子类实现Runnable接口。Java允许一个类同时实现多个接口,所以对于子类就比较方便。(建议使用)
5.匿名内部类的方式实现线程的创建
Thread的匿名内部子类
new Thread(){
@Override
public void run() {
System.out.println("as");
}
}.start();
Runnable的匿名内部子类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("创建了一个指定目标有名称的新线程");
}
},"线程").start();
线程安全
当多个线程同时操作一个全局变量,如果对这个变量只有读,那么线程是安全的,如果多个线程对一个全局变量有写的操作,那么线程不安全,因为线程是先取出变量的值,然后读写之后再给变量赋最终值,这样在实际应用中往往会发生错误,得不到预期值。
1.线程同步
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。Java中提供了同步机制(synchronized)来解决。
同步机制就是当一个线程在读写共享资源时,别的线程只能等待这个线程访问结束
有三种方式
1.同步代码块。2.同步方法。3.锁机制。
2.同步代码块
格式:
synchronized (同步锁){ 需要同步操作的代码 }
1.这个锁是一个对象,可以使任何类型(对象的同步锁就相当于给对象做了一个标记)
2.多个线程对象必须使用同一把锁
在任何时候,最多有一个线程拥有同步锁,谁有同步锁就可以进入代码块,其他只能等
示例:
public class 同步锁 extends Thread{
Object obj = new Object();
@Override
public void run() {
synchronized (obj){
System.out.println("拥有同步锁,进入代码块");
//...可以对共享资源读写
}
}
}
3.同步方法
使用synchronized修饰的方法,一个线程在执行此方法时,其他方法在外等待
对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。
public class 同步锁 extends Thread{
Object obj = new Object();
@Override
public synchronized void run() {
System.out.println("拥有同步锁,进入代码块");
//...可以对共享资源读写
}
}
4.锁机制、
java.util.concurrent.locks.Lock(接口),同步锁同步代码块有的功能lock锁都有,而且更强大,更能体现面向对象的特性
用法:
public void lock() :加同步锁。
public void unlock() :释放同步锁
示例:
public class 同步锁 extends Thread{
Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();//枷锁
System.out.println("拥有同步锁,进入代码块");
//...可以对共享资源读写
lock.unlock();//解锁
}
}
线程状态
1.六种状态线程:
1).新建:MyThread t = new MyThread();
2).可运行(待运行):t.start();
3).锁阻塞:运行后调用某个方法,但此方法已被其他线程“锁上了”。
4).无限等待:运行后,调用了“锁的wait()”方法。
5).计时等待:运行后,被调用了sleep(...);
6).被终止:run()方法正常运行完毕。
2.等待与唤醒
public class Demo {
private static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (obj) {
System.out.println("i = " + i);
if (i == 20) {
try {
//当前持有这把锁的线程,开始无限等待....
System.out.println("线程开始进入无限等待....");
obj.wait();
System.out.println("线程被唤醒.....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}.start();
System.out.println("主线程休息2秒...目的让前面的线程先运行...");
Thread.sleep(2000);
new Thread(){
@Override
public void run() {
synchronized (obj) {
//唤醒所有obj锁上等待的线程
System.out.println("我要唤醒所有等待的线程....");
obj.notifyAll();
}
}
}.start();
}
}
3.状态图: