文章目录
1.Thread
public class Demo1 {
public static void main(String[] args) {
MyThred m = new MyThred();//新建线程子对象
m.start(); //开启线程,执行run方法
for (int i = 0; i < 10000; i++) {
System.out.println("aaaaaaaaaaaaaaaaaaaaa");
}
}
}
//继承Thread类
class MyThred extends Thread {
@Override
public void run() { //重写run方法
for (int i = 0; i < 10000; i++) {
System.out.println("线程");
}
}
}
好处 : 可以直接使用Thread类中的方法 代码简单
弊端 : 如果已经有了父类 就不能使用这种方法 (java单继承)
2.创建实现runable方法 创建线程
public class demo_runable {
public static void main(String[] args) {
myRunnable mr = new myRunnable();//Runable是接口
Thread t = new Thread(mr);
t.start();
for (int i = 0; i < 10000; i++) {
System.out.println("aaaaaaaaaaa");
}
}
}
//实现runnable接口
class myRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
System.out.println("线程");
}
}
}
编译看父类 运行看子类
runable源码:
//1
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);}
//2
this.target = target; 局部变量 赋给成员变量
//3
@Override
public void run() {
if (target != null) {
target.run();
}
}
构造函数中传入了Runable的引用 成员变量记住了她 start调用run方法时
内部判断成员变量是否为空 执行子类的Run方法
好处
: 即使自己定的的线程有了父类也没有关系 因为有了父类 也可以实现接口 而且接口是可以多实现的
弊端
: 不能直接使用Thread的方法 需要先获取到线程对象后 才能得到Thread方法 代码复杂
new class(){} 继承这个类
3.Callable (重写call方法 能抛异常 有返回值)
匿名内部类 :
没有具体的类名 直接使用new class
public class demo_noName {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("bb");
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("aaaaaaaaaaaaaaa");
}
}
}).start();
}
}
获取修改线程名字 this.getName()
修改有两种 :
- 构造方法修改 直接传String
- this.setName(“String”)
获取当前线程对象 :
public class demo_current {
public static void main(String[] args) {
new Thread("String") {
@Override
public void run() {
System.out.println(getName());
}
}.start();
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
//获取正在执行的线程对象
System.out.println(Thread.currentThread().getName());
}
}
sleep
try {
Thread.sleep(1000); //毫秒 1s = 1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
守护线程 setDaemon :
相当于象棋里的 车马炮 非守护线程就是 帅
public class demo_setDaemon {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 1; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaa" + i);
}
}
};
Thread t3 = new Thread() {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(getName() + "...qqqqqqqqqqqqqqq" + i);
}
}
};
Thread t2 = new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "...b" + i);
}
}
};
t2.setDaemon(true);
t3.start();
t1.start();
t2.start();
}
}
加入线程(当前线程暂停 , 等待指定的线程执行结束后 当前线程再继续)
public class demo_join {
public static void main(String[] args) {
final Thread t1 = new Thread() { //final
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaa" + i);
}
}
};
Thread t2 = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
t1.join(1); //占有时间ms
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "...b" + i);
}
}
};
t2.start();
t1.start();
}
}
礼让线程 : yield
设置线程的优先级 ; setPriority(Thread.MAX_) //直接整数字也可
匿名内部类 使用局部变量 要用final修饰
同步代码块 : synchronized关键字 (🔒) //锁机制 锁对象可以是任意的 !!锁对象不能用匿名对象
public class demo_clock {
public static void main(String[] args) {
final Printer p = new Printer();
new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
p.print1();
}
}
}.start();
new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
p.print2();
}
}
}.start();
}
}
class Printer {
Demo d = new Demo();
public void print1() {
synchronized (d) {
System.out.print("你");
System.out.print("好");
System.out.print("啊");
System.out.print("xin");
System.out.print("yue");
System.out.println("\r");
}
}
public void print2() {
synchronized (d) {
System.out.print("lee");
System.out.print("s");
System.out.println("\r");
}
}
}
class Demo { //任意对象
}
同步方法 :
非静态的同步方法的锁对象是什么? this
静态的同步方法的锁对象是什么? 该类的字节码对象
class Printer{
public synchronized void print1() { //static
System.out.print("你");
System.out.print("好");
System.out.print("啊");
System.out.print("xin");
System.out.print("yue");
System.out.println("\r");
}
public void print2() {
synchronized (this) { //Printer.class
System.out.print("lee");
System.out.print("s");
System.out.println("\r");
}
}
}
线程安全问题 :
//一百张票 4个窗口同时卖
public class demo_demo {
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread {
private static int ticket = 1000; //注意 static
@Override
public void run() {
while (true) {
synchronized (Ticket.class) { //字节码对象
//不能是this 因为创建了四个对象
if (ticket == 0)
break;
try {
Ticket.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "第" + ticket-- + "号票");
}
}
}
}
a. 线程0来的时候 遇到 ==0 睡了 ; 线程1来 ==0 睡了 ; 线程2 来 睡了 ; 线程3 来 睡了 ;
然后 线程0苏醒 .执行 - - ; 线程1 苏醒 执行 - - ; …就会出现负值
b. 不加static 每个Ticket对象 都有一个ticket
c. 如果用引用数据类型成员变量当作锁对象 , 必须是静态的
//Runnable 实现
public class demo_demo2 {
public static void main(String[] args) {
Tickets t = new Tickets();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}//创建了一个对象当参数 传入Thread 开启四个线程
} //.start() 四次非法
class Tickets implements Runnable {
private int tickets = 100;
@Override
public void run() {
while (true) {
synchronized (this) { //this !!!!
if (tickets == 0)
break;
try {
Ticket.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "第"
+ tickets-- + "号票");
}
}
}
}
单例设计模式(掌握)
保证类在内存中只有一个对象
//饿汉式
class Singleton {
//1.私有构造方法 其他类就不能访问了
private Singleton() {
}
//2.创建本类对象
private static Singleton s = new Singleton();
//3.对外提供访问方法
public static Singleton getInstance(){ //获取实例
return s;
}
}
//懒汉式 , 单例的延迟加载模式
class Singleton{
//1.私有构造方法 其他类就不能访问了
private Singleton() {
}
//2.创建本类对象
private static Singleton s ;
//3.对外提供访问方法
public static Singleton getInstance(){ //获取实例
if (s == null) {
//线程1等待 线程2等待
s = new Singleton();
}
return s;
}
}
饿汉式 懒汉式区别
1.饿汉式是空间换时间 懒汉式是时间换空间
2.在多线程访问时 懒汉式不会创建多个对象 而懒汉式有可能会创建多个对象
//第三种
public class duo_single {
public static void main(String[] args) {
Singleton s1 = Singleton.s;
Singleton s2 = Singleton.s;
System.out.println(s1 == s2);
}
}
class Singleton{
//1.私有构造方法 其他类就不能访问了
private Singleton() {
}
//2.声明一个引用
public static final Singleton s = new Singleton();
}
Runtime类(单例)
Runtime r = Runtime.getRuntime(); //获取运行时对象
r.exec("shutdown -s -t 300");
Timer类 :计时器
public class duo_timer {
public static void main(String[] args) throws InterruptedException {
Timer t = new Timer();
//指定时间安排指定任务
t.schedule(new MyTimeTask(), new Date(120, 2, 2, 22, 53, 30));
while(true){
Thread.sleep(1000);
System.out.println(new Date());
}
}
}
class MyTimeTask extends TimerTask{
@Override
public void run() {
System.out.println("起床背英语");
}
}
两个线程间通信(掌握) :
等待唤醒机制 wait notify[All]
public class duo_Tongxin {
public static void main(String[] args) {
final Printer1 p = new Printer1();
new Thread(){
public void run() {
while(true){
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
new Thread(){
public void run() {
while(true){
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
class Printer1{
private int flag = 1;
public void print1() throws InterruptedException {
synchronized (this) {
if (flag!=1) {
this.wait();
}
System.out.print("明");
System.out.print("天");
System.out.print("你");
System.out.print("好");
System.out.println();
flag=2;
this.notify();
}
}
public void print2() throws InterruptedException {
synchronized (this) {
if (flag!=2) { //
this.wait();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
flag = 1;
this.notify(); //
}
}
}
三个以上线程通信
判断flag时 改成while ; 每次都判断
唤醒 要改成 notifyAll()
线程间通信注意的问题 :
在同步代码块中 用哪个对象锁 就用哪个对象调用wait方法
为什么wait方法和notify方法定义在Object这个类中?
因为锁对象可以是任意对象 Object
是所有 类的父类 , 所以wait方法 和notify
sleep 和 wait方法区别
a. sleep必须传入参数 参数就是时间 时间到了自动醒来
wait方法 可以传入参数 也可以不传入参数 ,传入参数就是在参数时间结束后等待
b.sleep方法在同步函数或同步代码块中 不释放锁
wait方法在同步函数或同步代码块中 释放锁
1.5新特性
互斥锁(掌握) : ReentrantLock Condition
可以指定唤醒 因此不用while 用if 即可 ;
public class duo_Lock {
public static void main(String[] args) {
final Printer2 p = new Printer2();
new Thread(){
public void run() {
while (true) {
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
new Thread(){
public void run() {
while (true) {
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
new Thread(){
public void run() {
while (true) {
try {
p.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
class Printer2{
private ReentrantLock r = new ReentrantLock();
private Condition c1 = r.newCondition();
private Condition c2 = r.newCondition();
private Condition c3 = r.newCondition();
private int flag = 1;
public void print1() throws InterruptedException {
r.lock(); //替换synchronized
if (flag!=1) {
c1.await();//this.wait();
}
System.out.print("明");
System.out.print("天");
System.out.print("你");
System.out.print("好");
System.out.println();
flag=2;
c2.signal(); //this.notifyAll();
r.unlock();
}
public void print2() throws InterruptedException {
r.lock();
if (flag!=2) {
c2.await();//this.wait();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
flag = 3;
c3.signal();//this.notifyAll();
r.unlock();
}
public void print3() throws InterruptedException {
r.lock();
while (flag!=3) {
c3.await();//this.wait();
}
System.out.print("v");
System.out.println();
flag = 1;
c1.signal();//this.notifyAll();
r.unlock();
}
}
多线程组的概述和使用: ThreadGroup
public class duo_group {
public static void main(String[] args) {
ThreadGroup tg = new ThreadGroup("线程组"); //创建新的线程组
myRunable my = new myRunable(); //创建Runnable的子类对象
Thread t1 = new Thread(tg, my, "李顺"); //将线程放在组中
Thread t2 = new Thread(tg, my, "lee");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
tg.setDaemon(true); //真个组 设置成守护线程
}
}
线程的五种状态 :
线程池的概述 : 省得 创建死亡过程 (尤其是创建短的线程)
所以 每一个线程结束后并不会死亡 而是回到线程池中成为空闲状态
ExecutorService
public class duo_chi {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);//创建线程池
pool.submit(new myRunable()); //将线程放进池子里并执行
pool.submit(new myRunable());
pool.shutdown(); //关闭线程池
}
}