多线程的一篇文章,个人对于多线程及其一些知识点的总结。
1.首先了解什么是线程:
线程是程序执行的路径。一个程序中可以有多条线程。
2. 多线程有什么用呢?
多线程并发可以提高程序的效率(同时执行多项任务,并发并行自己百度吧)。
多线程的两种方式:
(1)继承Thread类。
public class TextThread {
public static void main(String[] args) {
new FirstThread("One").start();//匿名创建线程并开启线程
}
}
class FirstThread extends Thread {
public FirstThread(String name) { // Thread都有一个名称 只要继承Thread方法
// 就可以调用super方法设置名称
super(name); // 调用父类的name
}
int index = 0;
public void run() {//必须重写run方法,
for (int index = 0; index < 100; index++) {
System.out.println(index + Thread.currentThread().getName());//获取当前子线程的名称
}
}
}
(2)实现Runnable接口。
package S;
public class TextThread {
public static void main(String[] args) {
new TextThread().Begin();
}
public void Begin() {
MyThread mt = new MyThread();
Thread t = new Thread(mt, "天狼王");//线程t
new Thread(mt, "王老二").start();//匿名方式启动子线程 线程2
t.start();
}
}
class MyThread implements Runnable { // 实现runnable接口并实现run方法
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
打印:
* 继承Thread
* 好处是:可以直接使用Thread类中的方法,代码简单
* 弊端是:如果已经有了父类,就不能用这种方法
* 实现Runnable接口
* 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
* 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
通过匿名内部类直接创建子线程:
方式一:
new Thread(“yyy”){//yyy线程名字
public void run(){}
}
方式二:
new Thread(new Runnable(){ //1,new 接口(){}实现这个接口
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("bb");
}
}
}).start();
多线程的休眠线程,加入线程,守护线程和礼让线程。
(1)sleep(休眠)
public class TextThread {
public static void main(String[] args) {
new TextThread().Begin();
}
public void Begin() {
MyThread mt = new MyThread();
Thread t = new Thread(mt, "天狼王");
//t.setDaemon(true);//守护线程
t.start();
try {
// t.join(); //加入线程 一直等待该线程执行完 才执行别的线程
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("main" + i);
//Thread.yield();// 礼让线程 当前线程下来
}
}
}
class MyThread implements Runnable { // 实现runnable接口并实现run方法
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + i);
try {
Thread.sleep(1000); // blocked
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
(2)join(加入)
把上面的代码join一行解开注释,sleep加上注释。
打印结果:调用join方法后,调用此方法的线程会强行抢占CPU,直到此线程执行完毕,才执行其他线程。
(3)setDaemon(true);//守护线程
把上面的代码一行解开注释,其他加上注释。main方法中的i最大改成5。
打印:设置为守护线程后,当其他线程执行完毕,守护线程会立即去结束自己的这个线程,没打印出来的...100就打印不了了。
(3)yield();//礼让线程(了解)
调用此方法后,当前线程下来,让其他线程抢占CPU.
多线程(同步代码块) 使用关键字
.什么情况下需要同步
* 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
* 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
* 2.同步代码块
(1)同步代码块:
package overClass;
public class Abnormal {
public static void main(String[] args) {
final Printer p = new Printer();
new Thread() {
public void run() {
while (true) {
p.print1();
}
}
}.start();
new Thread() {
public void run() {
while (true) {
p.print2();
}
}
}.start();
}
}
class Printer {
static Object d = new Object();
public static void print1() { // 两个线程持有同一把锁,相当于两个人用一把锁开门,一个人开门后,关上了,另一个人进不去,必须等待在门里面的人出来然后把钥匙给他,才能进去
synchronized (d) { // 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("人");
System.out.print("间");
System.out.print("天");
System.out.print("堂");
System.out.print("\r\n");
}
}
public static void print2() {
synchronized (d) {
System.out.print("十八");
System.out.print("层");
System.out.print("地");
System.out.print("狱");
System.out.print("\r\n");
}
}
}
打印:
(2)同步方法:
class Printer {
public static void print1() { // 两个线程持有同一把锁,相当于两个人用一把锁开门,一个人开门后,关上了,另一个人进不去,必须等待在门里面的人出来然后把钥匙给他,才能进去
synchronized (Printer.class) { // 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("人");
System.out.print("间");
System.out.print("天");
System.out.print("堂");
System.out.print("\r\n");
}
}
/*
* 非静态同步函数的锁是:this 静态的同步函数的锁是:字节码对象
*/
public static synchronized void print2() {
System.out.print("十八");
System.out.print("层");
System.out.print("地");
System.out.print("狱");
System.out.print("\r\n");
}
}
线程安全问题,多个线程修改一个变量(售票)把这个变量声明称static,避免并发带来的错误。
end:死锁(了解)有两把钥匙,线程一拿到钥匙一,缺钥匙二,而线程二拿到钥匙二,缺钥匙一,又在while循环中无法退出。造成了死锁。
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread() {
public void run() {
while(true) {
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "开吃");
}
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "开吃");
}
}
}
}
}.start();
}