多线程
什么是线程?
线程是程序执行的,一条路径,一个进程包含多想工作。
多线程应用场景
红蜘蛛,同时共享屏幕给多台电脑。
迅雷,开启多条线程一起下载。
qq。可以同时和多个人一起视频
多线程并行和并发的区别
并行:就是两个任务同时运行,甲任务进行的同时,乙任务也在进行(需要多核cpu)
并发:两个任务都在请求运行,而处理器只能接受一个任务,就把两个任务安排轮流进行,由于时间建个短,使人感觉两个任务都在进行。
java程序运行原理和jvm虚拟机的启动是单线程
多线程实现方法一
继承Thread类
1.定义类基础Thread
2.重写run方法
3.把想让线程感到活写在run方法中。
4.创建线程对象。
5.开启线程,内部会自动执行run方法(Start())。
public class Demo extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("aa=====================");
}
}
}
public class Demo1 {
public static void main(String[] args) {
Demo d=new Demo();
//开启线程的方法
d.start();
for (int i = 0; i < 1000; i++) {
System.out.println("bb");
}
}
}
多线程实现方法二
实现Runnable接口
1.定义类实现Runnable接口
2.重写run方法
3.把要做到事情放到run方法中
4.创建自定义的Runnable子类对象
5.创建Thread对象,传入Runnable
6.调用start方法,开启线程
public class Demo2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println("===============");
}
}
}
public class Demo3 {
public static void main(String[] args) {
Demo2 d=new Demo2();
Thread t=new Thread(d);
t.start();
for (int i = 0; i < 300; i++) {
System.out.println("-------------");
}
}
}
两种方法的区别*
a:继承Thread:由于子类重写了Thread类的run()方法,当调用start()是,直接找子类的run方法。
b:实现Runnable接口:构造函数中传入Runnable的引用成员遍历记住了它,start调用run方法时,内部判断成员遍历Runnable的引用是否为空,不为空编译的时候看的Runnable的run,运行时执行的是子类run方法。
继承Thread
好处:可以直接使用Thread类中的方法,代码简单。
弊端:如果已经有父类,就不能用这种方法(尽量不用)
实现Runnable接口
好处:即使自定义的线程已经有了父类也没关系,原因接口可以多实现。
弊端:不能直接使用Thread中的方法start,如果要使用先获取到线程对象,然后才能得到Thread的方法,代码复杂(推荐使用)
获取名字和设置名字
1.获取名字
通过getName方法获取线程对象的名称。
2.设置名称
1.通过构造函数传入String类型的名称
2.通过set函数。
public class Demo4 {
public static void main(String[] args) {
//初始化赋值改名
new Thread("线程一") {
@Override
public void run() {
System.out.println(this.getName()+"aaaa");
}
}.start();
Thread t1=new Thread() {
public void run() {
//set修改,改名
//this.setName("线程二");
System.out.println(this.getName()+"bbbb");
};
};
//方法二升级set改名
t1.setName("线程三");
t1.start();
}
}
线程休眠
换算比:1秒=1000毫秒=1000X1000X1000纳秒
不表明需求,默认为纳秒,windos不支持会报错。
如果创建两个线程,写入休眠,不会让出cpu。
public static void main(String[] args) throws InterruptedException {
for (int i = 20; i >0; i--) {
Thread.sleep(1000);;//1000毫秒等于1秒
System.out.println("倒计时"+i+"秒");
}
}
守护线程
cpu运行惯性会使守护线程多运行几次才会结束
加入线程(join())
当前线程暂停,等待指定的线程执行结束后,当前线程在继续执行。
join(参数,代表的是时间int类)可以等待指定的毫秒之后在继续运行。
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread("a") {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"=========");
}
}
};
Thread t2=new Thread("b") {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i==2) {
try {
t1.join(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(getName()+"xxxxxxx");
}
}
};
t1.start();
t2.start();
}
礼让线程(不明显,了解)
Thread.yield();//让出cpu
设置线程优先级
setPriority();
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread("a") {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"=========");
}
}
};
Thread t2=new Thread("b") {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"xxxxxxx");
}
}
};
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
同步代码块
使用sgnchronized关键字加上一个锁对象来定义一段代码,这就叫同步代码块。
锁芯可以是任意对象,同步代码块可以保证数据的完整性。
@Override
public void run() {
while(true) {
synchronized (Demo1.class) {
if(ticet<=0) {
break;
}
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
System.out.println(getName()+"----第"+ticet--+"张票");
}
}
public static void main(String[] args) {
new Demo1().start();
new Demo1().start();
new Demo1().start();
new Demo1().start();
}
线程安全问题
多线程并发操作同一次数据,就可能出现线程安全。
使用同步技术可以解决这个问题,把操作数据的代码进行同步,不要多个线程一起操作。
public class Demo2 implements Runnable{
private int ticet=100;
@Override
public void run() {
while(true) {
synchronized (Demo2.class) {
if(ticet<=0) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"----第"+ticet--+"张票");
}
}
public static void main(String[] args) {
Demo2 d=new Demo2();
new Thread(d).start();;
new Thread(d).start();;
new Thread(d).start();;
new Thread(d).start();;
}
}
死锁
多线程同步的时候,如果同步代码镶嵌,使用的锁芯相同,就可能会出现死锁。
总结:开发的时候涉及到锁,切记不要区嵌套。
public class Demo1{
private static String s1="左筷子";
private static String s2="右筷子";
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread() {
@Override
public void run() {
while(true) {
synchronized (s1) {
System.out.println(getName()+" "+s1);
synchronized (s2) {
System.out.println(getName()+" "+s2);
}
}
}
}
}.start();
new Thread() {
@Override
public void run() {
while(true) {
synchronized (s2)
{
System.out.println(getName()+" "+s2);
synchronized (s1) {
System.out.println(getName()+" "+s1);
}
}
}
}
}.start();
}
}