1、创建线程
1.1、继承Thread类
package com.xusheng;
public class MyThread extends Thread{
public void run() {
System.out.println("this is a thread");
}
}
调用:
Thread t = new MyThread();
t.start();
1.2、实现Runnable接口
package com.xusheng;
public class MyThread2 implements Runnable{
public void run() {
System.out.println("this is b thread");
}
}
调用:
MyThread2 t2 = new MyThread2();
Thread t = new Thread(t2);
t.start();
以上两种方式都可以创建并启动一个新的线程,但是在平时的使用当中我们使用的更多的是第二种方式。因为在java中类是单继承的,而接口是多继承的。并且我们在使用线程时经常会使用匿名内部类来进行线程的创建和调用。如果我们在主方法中调用的是run()方法时,程序并不会并发执行,而是当做普通方法进行调用
public static void main(String[] args) {
new Thread(new Runnable(){
public void run() {
System.out.println("this is c thread");
}
}).start();;
}
2、线程中的一些常用方法
Thread(String name) 初始化线程的名字
getName() 返回线程的名字
setName(String name) 设置线程对象名
sleep() 线程睡眠指定的毫秒数。
getPriority() 返回当前线程对象的优先级 默认线程的优先级是5
setPriority(intnewPriority) 设置线程的优先级 虽然设置了线程的优先级,但是具体的实现取决于底层的操作系统的实现(最大的优先级是10 ,最小的1 , 默认是5)。
currentThread() 返回CPU正在执行的线程的对象
setDaemon() 设置线程为后台线程
3、改变线程的状态的方法
3.1、sleep()方法:其可以指定让线程“睡眠”几毫秒
public static void main(String[] args) throws InterruptedException {
MyThread2 tt1 = new MyThread2();
MyThread3 tt2 = new MyThread3();
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt2);
t1.sleep(5000);
t1.start();
t2.start();
}
在这里我们调用了sleep()方法,但是要注意的是,我们这里使用t1线程进行调用,我们也可以使用Thread.sleep()方法,在这里这两种方式调用其实产生的效果是一致的,都是让main()方法休眠5秒,而不是t1方法休眠5秒。所以sleep()方法其实是在哪个方法中被调用就使这个方法休眠5秒
3.2、 yield()方法:指定线程将cpu资源让出,自己回到runnable状态
package com.xusheng;
public class MyThread2 implements Runnable{
public void run() {
Thread.yield();
for(int i=1;i<=1000;i++){
System.out.println("thread1");
}
}
}
3.3、join()方法:用于等待当前方法结束
package com.xusheng;
public class _Main {
public static void main(String[] args) throws InterruptedException {
MyThread2 tt1 = new MyThread2();
MyThread3 tt2 = new MyThread3();
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt2);
t2.join();
t1.start();
t2.start();
System.out.println("main");
}
}
4、线程间的协作(通信)
wait()和notify()方法:
实体类:
package com.xs1;
public class Product {
public String name;
public int price;
public boolean flag;
}
生产者:
package com.xs1;
public class Producer extends Thread{
Product p;
public Producer(Product p) {
this.p = p;
}
public void run(){
create();
}
public void create(){
int i = 0;
while(true){
synchronized(p){
if(p.flag == false){
if(i%2 == 0){
p.name = "苹果";
p.price = 10;
}else{
p.name = "香蕉";
p.price = 5;
}
System.out.println("生产者:"+p.name+":"+p.price);
i++;
p.flag = true;
p.notify();
}else{
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
消费者:
package com.xs1;
public class Consumer extends Thread{
Product p;
public Consumer(Product p) {
this.p = p;
}
public void run(){
consume();
}
public void consume(){
while(true){
synchronized(p){
if(p.flag == true){
System.out.println("消费者:"+p.name+":"+p.price);
p.flag = false;
p.notify();
}else{
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
wait()方法将线程挂起,这时,wait()方法会释放锁,直到线程得到了notify()消息,这时线程才会进入就绪状态
5、线程的死锁问题
线程一:
package com.xs2;
public class MyThread1 implements Runnable{
public void run() {
method1();
}
public void method1(){
synchronized("suo1"){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized("suo2"){
for(int i=1;i<=10000;i++){
System.out.println("Thread1的 method1");
}
}
}
}
}
package com.xs2;
public class MyThread2 implements Runnable{
public void run() {
method1();
}
public void method1(){
synchronized("suo2"){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized("suo1"){
for(int i=1;i<=10000;i++){
System.out.println("Thread2的 method1");
}
}
}
}
}
线程死锁就是一个任务在等待另一个任务,而后者又在等待前一个任务。当这里的线程1开始执行时,获得suo1对象,然后线程休眠1秒,将cpu资源分配给了线程2,此时线程2开始执行,获得suo2对象,此时线程2又开始休眠,此时线程1想要继续往下执行,必须获得suo2对象,而线程2又没有将suo2对象释放。线程2想要继续往下执行,但发现线程1没有释放suo1对象,所以导致两个线程一直等待对方先执行完
线程死锁的条件:
(1)互斥条件
(2)至少有一个任务它必须持有一个资源且正在等待一个当前被别的任务持有的资源
(3)资源不能被任务抢占,任务必须把资源释放当做普通事件
(4)必须有循环等待
发生死锁的话必须要满足以上四个条件。要防止死锁的话只要破坏上述四个条件中的任何一个就可以,最容易破坏的就是第四个