进程与线程:一个进程可以启动多个线程
1.创建线程的两种方法
a.继承java.lang.Thread类,重写run()方法,该方法相当于程序的入口,最后在通过线程对象.start()方法启动线程
public class Test_01 {
public static void main(String[] args) {
// 创建线程对象(继承)
Thread thread = new Processor();
// 启动线程
thread.start();
}
}
class Processor extends Thread {//继承创建线程
@Override
public void run() {
play();
}
public void play() {
for (int i = 0; i < 10; i++) {
System.out.println("继承Thread的线程启动了:" + i);
}
}
}
b.实现java.lang.Runnable接口,再实现run()方法,最后在用线程对象调用start()方法启动线程
public class Test_01 {
public static void main(String[] args) {
// 创建线程对象(实现)
// new Thread(Runnable target)
Thread thread = new Thread(new Processor());
// 启动线程
thread.start();
}
}
class Processor implements Runnable {//实现Runnable接口
@Override
public void run() {
play();
}
public void play() {
for (int i = 0; i < 10; i++) {
System.out.println("实现Runnable的线程启动了:" + i);
}
}
}
2.线程的生命周期:
新建:new语句创建完成时
就绪:执行start()之后
运行:占用CPU时
阻塞:执行wait()语句后或执行sleep()语句后或等待某个对象锁时
终止:run()执行完成
3.线程的控制方法:
a.join():当前线程与指定线程合并,与其他线程无关
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Processor5();
Thread t2 = new Processor5();
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
/**
* 调用某线程的该方法,将当前线程与该线程"合并"
* 即等待该线程结束后,再回复当前线程的运行
*/
t1.join(); // 让当前main线程等待t1线程执行完后再执行
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
b.yield():暂停当前正在执行的线程,让其他线程执行(写在那个线程中,就暂停哪个线程)
public static void main(String[] args) {
Thread t1 = new Process6();
t1.setName("t1");
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
if (i % 2 == 1) {
// 当i为奇数时,暂停main线程,让t1线程优先执行
Thread.yield();
}
}
}
c.sleep():让当前线程睡眠,写在哪个线程就睡眠哪个线程
唤醒线程:1)正常唤醒(睡眠时间到了) 2)异常唤醒: 线程对象.interrupt();
public class _03_Interrupt {
public static void main(String[] args) {
Thread thread = new Thread(new Processor4());
// setName():设置线程名
thread.setName("t1");
thread.start();
/**
* main线程睡眠1s,而t1线程睡眠3s
*
* 所以结果为t1是属于异常唤醒
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 异常唤醒
thread.interrupt();
}
}
class Processor4 implements Runnable {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("睡醒了...");
} catch (Exception e) {
e.printStackTrace();
System.out.println("异常唤醒...");
}
System.out.println("-----------");
}
}
c.setDaemon(boolean flag):设置一个指定的守护线程
Thread t1 = new Processor10();
// 把t1设置成守护线程,会随着主线程而死亡
t1.setDaemon(true);
t1.setName("t1");
t1.start();
/**
* 由于主线程main执行了5次,所以守护线程t1也循环5次结束
*/
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
d.
wait():该线程进入等待状态,如果被唤醒之后,接着当前等待的地方继续执行(用于成员方法中)
notify():随机唤醒一个在该对象上等待的线程
notifyAll():唤醒所有在该对象上等待的线程
4.锁(Lock与Synchronized)
Lock:块锁,可以锁住任意行代码
//创建锁
Lock lock = new ReentrantLock();
修饰符 返回值类型 方法名(参数列表) {
// 开启同步
lock.lock();
/**
* 需要上锁的同步代码
*/
// 取消同步
lock.unlock();
}
Synchronized:
注:
如果访问了一个类的加锁的静态方法的时候,该类所有加着synchronized修饰的静态方法,全部被锁定
public class _11_Synchronized {
public static void main(String[] args) {
Thread t1 = new Processor11();
Thread t2 = new Processor11();
Thread t3 = new Processor11();
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
class Processor11 extends Thread {
/**
* 运行结果:<br>
* m3执行了<br>
* m1执行了<br>
* m2执行了
*/
@Override
public void run() {
//m1,m2均被synchronized修饰,所以访问m1时,m2也会被锁定
if ("t1".equals(Thread.currentThread().getName())) {
Processor11.m1();
} else if ("t2".equals(Thread.currentThread().getName())) {
Processor11.m2();
} else if ("t3".equals(Thread.currentThread().getName())) {
Processor11.m3();
}
}
//类中加锁的静态方法
public synchronized static void m1() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m1执行了");
}
//类中加锁的静态方法
public synchronized static void m2() {
System.out.println("m2执行了");
}
//类中未加锁的静态方法
public static void m3() {
System.out.println("m3执行了");
}
}
如果访问了一个对象的加锁的成员方法的时候,该对象所有加着synchronized修饰的成员方法,都会锁定