//有两种开启线程的方法
//* 第一种创建线程的方式:
* 1:继承Thread
* 2:重写run方法
* 优点: 继承线程并重写run方法的形式优点在于结构简单,利于使用匿名内部类形式创建.
* 缺点主要有两个:
* 1:由于java是单继承的,导致如果继承了Thread就不能再继承其它类了,这在实际开发时非常不方便.
* 2:在定义线程同时重写run方法来定义任务,这导致线程与任务存在必然的耦合关系,不利于线程的重用.
Thread t1 = new MyThread1();
Thread t2 = new MyThread2();
//线程的启动要调用start方法,而不是直接调用run方法.
t1.start();
t2.start();
class MyThread1 extends Thread{
public void run(){
for(int i=0;i<1000;i++){
System.out.println("你是谁啊?");
}
}
}
class MyThread2 extends Thread{
public void run(){
for(int i=0;i<1000;i++){
System.out.println("开门,查水表的!");
}
}
//* 第二种创建线程的方式:
// * 实现Runnable接口单独定义线程任务.
*/ //1实例化任务
Runnable r1 = new MyRunnable1();
Runnable r2 = new MyRunnable2();
//2创建线程
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable{
public void run(){
for(int i=0;i<1000;i++){
System.out.println("你是谁啊?");
}
}
}
class MyRunnable2 implements Runnable{
public void run(){
for(int i=0;i<1000;i++){
System.out.println("我是查水表的!");
}
}
//还可以使用匿名内部类的方法创建线程
//方式1:继承Thread重写run方法
Thread t1 = new Thread(){
public void run(){
for(int i=0;i<1000;i++){
System.out.println("你是谁啊?");
}
}
};
//方式2:实现Runnable接口单独定义任务
Runnable r2 = () -> {
for(int i=0;i<1000;i++){
System.out.println("我是查水表的!");
}
};
Thread t2 = new Thread(r2);
// Thread t2 = new Thread(()->{
// for(int i=0;i<1000;i++){
// System.out.println("我是查水表的!");
// }
// });
t1.start();
t2.start();
Thread中的相关方法
//获取主线程 Thread t = Thread.currentThread();
//获取唯一标识 long id = t.getId();
//获取线程优先级 1-10 默认值为5 int priority = t.getPriority();
//线程是否活着 boolean isAlive = t.isAlive();
//是否为守护线程 boolean isDaemon = t.isDaemon();
//是否被中断了 boolean isInterrupted = t.isInterrupted();
//主动要求线程放弃本次剩余时间片.模拟执行到这里时没时间发生切换 Thread.yield();
/**
* java中所有的代码都是靠线程执行的,main方法也不例外,运行main方法的线程是JVM创建的,并且取名为"main"
* 我们称它为主线程.
*
* 线程提供了一个静态方法:
* static Thread currentThread()
* 该方法可以获取运行这个方法的线程
*/
Thread main = Thread.currentThread();
System.out.println("主线程:"+main);
dosome();
}
public static void dosome(){
Thread t = Thread.currentThread();
System.out.println("运行dosome方法的线程是:"+t);
}
/**
* 守护线程
* 守护线程是通过普通线程(我们正常创建的线程.普通线程也称为前台线程,用户线程)调用方法setDaemon(true)
* 设置转变而来的.
* 守护线程与普通线程的区别是进程结束时的一个区别:
* 当java进程中所有的普通线程都结束时,进程就会结束,此时会强制杀死所有还在运行的守护线程.
*/ Thread rose = new Thread("rose"){
public void run(){
for(int i=0;i<5;i++){
System.out.println(getName()+":let me go!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println(getName()+":啊啊啊啊啊啊 AAAAAAAAaaaaaa....");
System.out.println("噗通");
}
};
Thread jack = new Thread("jack"){
public void run(){
while(true){
System.out.println(getName()+":you jump! i jump!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
rose.start();
//注意,设置守护线程这件事必须在线程启动前进行!否则会抛出异常
jack.setDaemon(true);
jack.start();
// while(true);
/**
* 线程的优先级
* 线程有10个优先级,分别用整数1-10表示。其中1为最低,5为默认,10为最高优先级。
*
* 当线程调用start方法后就纳入到了线程调度器中被统一管理,此时只能被动的被分配时间片并发运行。线程不能
* 主动索取时间片。通过调整线程的优先级可以最大程度的调节获取时间片的概率。
* 线程优先级越高的线程获取时间片的次数越多。
*
*/
Thread min = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("min");
}
}
};
Thread norm = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("nor");
}
}
};
Thread max = new Thread(){
public void run(){
for(int i=0;i<10000;i++){
System.out.println("max");
}
}
};
// min.setPriority(1);
min.setPriority(Thread.MIN_PRIORITY);//设置为最小优先级
max.setPriority(Thread.MAX_PRIORITY);//设置为最高优先级
min.start();
norm.start();
max.start();
/**
* 线程的静态方法:
* static void sleep(long ms)
* 该方法可以让运行这个方法的线程处于阻塞状态指定毫秒
*/
/**
* 当一个线程调用sleep方法处于睡眠阻塞的过程中若该线程的interrupt方法被调用,则会打断其睡眠阻塞状态,
* 此时sleep方法会抛出中断异常:InterruptedException
*/
Thread lin = new Thread("林永健") {
public void run(){
System.out.println(getName()+":刚美完容,睡一会吧...");
try {
Thread.sleep(50000000);
} catch (InterruptedException e) {
System.out.println(getName()+":干嘛呢!干嘛呢!干嘛呢!都破了相了!");
}
System.out.println(getName()+":醒了");
}
};
Thread huang = new Thread("黄大锤"){
public void run(){
System.out.println(getName()+":大锤80,小锤40,开始砸墙!");
for(int i=0;i<5;i++){
System.out.println(getName()+":80!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("咣当!");
System.out.println(getName()+":大哥!搞定!");
lin.interrupt();//中断lin的睡眠阻塞
}
};
lin.start();
huang.start();
/**
* 多线程并发安全问题:
* 当多个线程并发操作同一临界资源,由于线程切换实际不确定,导致操作临界资源的完整过程出现混乱从而导致各种
* 不良后果.
* 临界资源:操作该资源的完整过程同一时刻只能被单线程进行的资源.
*/
/**
* 有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高并发效率.
* 同步块:
* synchronized(同步监视器对象){
* 需要同步执行的代码片段
* }
*/
/**
* 成员方法上使用synchronized,同步监视器对象不可选,就是this
*/
/**
* 静态方法上使用synchronized,那么该方法一定具有同步效果.
*/
/**
* 互斥性
* 当使用多个synchronized锁定多个代码片段并且指定的同步监视器对象是同一个时,这些代码片段之间就是互斥的
*/