线程的创建方法
- 继承Thread父类,重写run方法;
开启时new一个对象直接调用start()方法开启线程; - 实现Runnable接口,重写run方法;
开启是先创建一个Thread的对象,在构造方法中写入一个runnable接口,即new Thread(this).start()。 - 匿名内部类法,如下
new Thread(){
public void run(){
}
}.start();
线程的常见方法:
类方法(静态,用类名去调用的方法)
1.sleep(); 休眠方法,会发生中断异常,即ThreadinterruptedException;
2.currentThread(); 获取当前线程;
3.yield();
对象方法(用类的对象去调用的方法)
- getName(); 当前线程的名字
- getPriority(); 优先级 【1,10】(默认值为5)。 具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器时间。然而,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
- setDaemon(true) ; 设置守护线程 GC:垃圾回收器,他是一个守护线程,一般的Thread 都是用户线程
线程安全
线程不安全的前提
- 开启多个线程;
- 多个线程有公共的资源;
- 同时修改。
解决方法
使用同步锁synchronized
- 使用同步方法,即用synchronized修饰的方法;
- 使用同步代码块,即用synchronized修饰的代码块。
notify()、notifyAll、wait()、sleep()
- notify(); 唤醒一个等待线程,进入可执行状态;
- wait(); 释放cup,将CPU让出给别的线程使用,并释放同步锁,将此线程 放入等待池;
- notifyAll() ; 唤醒所有等待池中的线程;
- notify()、notifyAll、wait() 方法被锁对象调用,且在同步方法或同步代码块中调用。
- sleep(),会发生中断异常,即ThreadinterruptedException,让出cpu,不释放锁。
实例:妖的故事
String name;
String sex;
Object lock = new Object();
int x = 0;
class Set implements Runnable {
public void run() {
while (true) {
public synchronized void set() {
if (x == 0) {
name = "Mark";
sex = "男";
} else {
name = "Lucy";
sex = "女";
}
notify();
try {
wait();//释放CPU和锁
} catch (InterruptedException e) {
e.printStackTrace();
}
x++;
x %= 2;
}
}
}
}
class Get implements Runnable {
public void run() {
while (true) {
public synchronized void get() {
System.out.println(name + " " + sex);
notify(); // 唤醒一个wait等待的线程
try {
wait();//释放CPU和锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
Resource resource = new Resource();
Set set = resource.new Set();
Get get = resource.new Get();
new Thread(set).start();
new Thread(get).start();
}
一个线程的生命周期
线程的几种状态之间的转换:创建(new)、运行(runnable)、阻塞(waiting 、 timed waiting、blocked)和死亡(terminate)。
在给定时间点上,一个线程只能处于一种状态。这些状态是虚拟机状态,它们并没有反映所有操作系统线程状态。
单例模式
单例是指该类只能创建一个对象,故将构造方法私有。
package sychronized;
public class SIngletonInstance {
// 恶汉 在定义的时候new
// private static SIngletonInstance instance = new SIngletonInstance();
// private synchronized static SIngletonInstance getInstance(){
// return instance;
// }
// 懒汉 定义的时候不new 方法体才new
private static SIngletonInstance instance;
public SIngletonInstance getInstance() {
if (instance == null) {
synchronized (SIngletonInstance.class) {
if (instance == null) {
instance = new SIngletonInstance();
}
}
}
return instance;
}
}
死锁问题
在Java中,每一个 Object 对象都有一个隐含的锁,这个也称作监视器对象。在进入 synchronized 之前自动获取此内部锁,而一旦离开此方式,无论是完成或者中断都会自动释放锁;其次若不适用object对象的锁,就可使用<类名.class>获取锁。
死锁问题的产生:
- 锁的嵌套使用;
- 多个线程公用一把锁,拿到锁后不相让。
package sychronized;
public class ChopSticks extends Thread {
static String firstChopSticks = new String();
static String sencondChopSticks = new String();
String name;
public ChopSticks(String name) {
this.name = name;
}
public void run() {
if (name.equals("yi")) {
synchronized (firstChopSticks) {
System.out.println("get first!!");
synchronized (sencondChopSticks) {
System.out.println("get sencond");
}
}
}
if (name.equals("ji")) {
synchronized (sencondChopSticks) {
System.out.println("get sencond");
synchronized (firstChopSticks) {
System.out.println("get first!!");
}
}
}
}
public static void main(String[] args) {
ChopSticks ch1 = new ChopSticks("yi");
ChopSticks ch2 = new ChopSticks("ji");
Thread thread = new Thread(ch2);
thread.start();
Thread thread2 = new Thread(ch1);
thread2.start();
}
}