public class main {
public static void main(String[] args) {
yf yjl=new yf();
//注意:
//需要调用 start方法开启线程
//start方法会开启一个新线程,来执行润方法
//如果直接调用run方法,则方法不会进入就绪态
yjl.start();
System.out.println("主线程执行结束");
}
static class yf extends Thread{
/*
从写run方法
将需要并发执行的方法写在run里
*/
public void run(){
for(int i=1;i<=10;i++)
System.out.println(i);
}
}
}
执行结果
补充:
1.如果一个start调用了一个已经启动的线程,会抛出illegalthreadstateexception的异常
2.thread类实现runnable接口,其中run()方法正是对runnable接口中的run()方法的具体实现
3.runnable接口的存在是为了类需要继承其他类时(只能继承一个类)也能实现多线程
2.通过Thread实例化对象
public class main {
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
for(int i=1;i<=20;i++)
System.out.println(i);
}
};
Thread yf1=new Thread(yf);
yf1.start();
System.out.println("主线程");
}
}
线程的常用方法:
1.线程名字的设置
import javax.lang.model.element.NestingKind;
public class main {
public static void main(String[] args) {
//方法1
Thread yf=new Thread();
yf.setName("lover");
System.out.println(yf.getName());
//方法二:应该直接thread一个对象作用不大,故此方法很少用
Thread yf1=new Thread("yf1");
System.out.println(yf1.getName());
//方法3
Runnable yjl=new Runnable() {
@Override
public void run() {
System.out.println("loveyou");
}
};
Thread yf2=new Thread(yjl,"yf2");
System.out.println(yf2.getName());
//方法4
Thread2 yf3=new Thread2("喜洋洋");
System.out.println();
}
}
class Thread2 extends Thread{
public Thread2 (){}
public Thread2(String name){
super.setName(name);
//或 this.setName(name);
}
}
2.线程的休眠
import javax.lang.model.element.NestingKind;
public class main {
public static void main(String[] args) {
yf1 yjl1=new yf1("yjl1");
yf2 yjl2=new yf2("yjl2");
yjl1.start();
yjl2.start();
}
}
class yf1 extends Thread{
yf1(String name){
super.setName(name);
}
public void run() {
for(int i=1;i<=10;i++){
System.out.println(getName()+" "+i);
if(i==5) {
try {
this.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class yf2 extends Thread{
yf2(String name){
super.setName(name);
}
public void run() {
for(int i=1;i<=10;i++){
System.out.println(getName()+" "+i);
if(i==3) {
try {
this.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
可以看出 yjl2执行到3后 休眠1秒 yjl1在这段时间应该没人和它抢时间片,所以一直在输出
3.线程的优先级:优先级高的只是具有更大的概率,优先级的设置是一个【0,10】的整数 默认是5
注意:设计线程优先级必须放在该线程执行(start)之前
public class main {
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
for(int i=1;i<=10;i++)
System.out.println(Thread.currentThread().getName()+" "+i);
}
};
Thread yf1=new Thread(yf,"yf1");
Thread yf2=new Thread(yf,"yf2");
Thread yf3=new Thread(yf,"yf3");
yf3.setPriority(1);
yf1.setPriority(10);
yf2.setPriority(5);
yf1.start();
yf2.start();
yf3.start();
}
}
可见 优先级高的抢到的几率更大
4.线程的加入:当在执行某个线程A,如果插入线程B,线程A会等待线程B执行完成后执行
import javax.lang.model.element.NestingKind;
public class main {
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
for(int i=1;i<=10;i++)
System.out.println(Thread.currentThread().getName()+" "+i);
}
};
Thread yf1=new Thread(yf,"yf1");
Runnable yjl=new Runnable() {
@Override
public void run() {
for(int i=1;i<=10;i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if(i==5) {
try {
yf1.start();
yf1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Thread yjl1=new Thread(yjl,"yjl1");
yjl1.start();
}
}
5.线程的中断:以往的时候会用stop来中断线程,但现在已经废弃了,不建议使用stop方法来停止一个线程,现在提倡在run方法中使用无限循环的形式,然后使用一个布尔类型标记控制循环的停止
6.线程的礼让:指的是当前运行状态的内存,去放弃自己的cpu时间片,由运行状态回到就绪状态,假设A和B在同时抢cpu时间片 不一定A礼让后一定执行B,A礼让过后会和B重新争抢,A仍有可能抢到
import javax.lang.model.element.NestingKind;
public class main {
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
for(int i=1;i<=10;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==5)
Thread.yield();
}
}
};
Thread yf1=new Thread(yf,"yf1");
Thread yf2=new Thread(yf,"yf2");
yf1.start();
yf2.start();
}
}
临界资源问题:被多个线程共享的资源
如下代码,我们模拟了3个人卖苹果
import javax.lang.model.element.NestingKind;
public class main {
public static int allapple=200;
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
while(allapple>0){
allapple--;
System.out.println(Thread.currentThread().getName()+"卖出一个苹果剩余苹果数为"+allapple);
}
}
};
Thread kangkang =new Thread(yf,"kangkang");
Thread Trump=new Thread(yf,"Trump");
Thread me=new Thread(yf,"me");
kangkang.start();
Trump.start();
me.start();
}
}
从结果可以看出 这个数据是存在问题,这就是临界资源问题(注意 虽然没有任何规律,但每个数只出现了一次);
问题产生的原因:因为我们同时存在3个线程,三个线程在抢cpu,假设kangkang抢到了cpu 执行了allapple-- ,数值才传给输出语句,cpu时间片就被其他的线程抢了,导致输出语句没有执行出来,就是这个原因导致了输出数值的无序性,但每个该出现的数字都出现了
怎么解决这个问题了,我们只需要防止多个线程同时对这个数据操作就行,这里我们引入锁的概念
方法1:同步代码段
import javax.lang.model.element.NestingKind;
public class main {
public static int allapple=200;
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
while(allapple>0){
synchronized (""){
allapple--;
System.out.println(Thread.currentThread().getName()+"卖出一个苹果剩余苹果数为"+allapple);
}
}
}
};
Thread kangkang =new Thread(yf,"kangkang");
Thread Trump=new Thread(yf,"Trump");
Thread me=new Thread(yf,"me");
kangkang.start();
Trump.start();
me.start();
}
}
synchronized是一个同步锁,它修饰的对象有以下几种:
- 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
- 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
可以这样理解,凡是被synchronized修饰的 类(…)对其进行操作都需要一把钥匙(钥匙仅有一把),只有抢到了钥匙的线程才能执行
但代码结果还是有问题,为什么了 因为while(allapple>0不在锁类
加个判断就行
import javax.lang.model.element.NestingKind;
public class main {
public static int allapple=200;
public static void main(String[] args) {
Runnable yf=new Runnable() {
@Override
public void run() {
while(allapple>0){
synchronized (""){
if(allapple<=0)
break;
allapple--;
System.out.println(Thread.currentThread().getName()+"卖出一个苹果剩余苹果数为"+allapple);
}
}
}
};
Thread kangkang =new Thread(yf,"kangkang");
Thread Trump=new Thread(yf,"Trump");
Thread me=new Thread(yf,"me");
kangkang.start();
Trump.start();
me.start();
}
}
显示锁(Reentrantlock):
import javax.lang.model.element.NestingKind;
import java.util.concurrent.locks.ReentrantLock;
public class main {
public static int allapple=200;
public static void main(String[] args) {
ReentrantLock lock=new ReentrantLock();
Runnable yf=new Runnable() {
@Override
public void run() {
while(allapple>0){
lock.lock();//上锁
if(allapple<=0)
break;
System.out.println(Thread.currentThread().getName()+"卖出一个苹果剩余苹果数为"+--allapple);
lock.unlock();//解锁
}
}
};
Thread kangkang =new Thread(yf,"kangkang");
Thread Trump=new Thread(yf,"Trump");
Thread me=new Thread(yf,"me");
Trump.start();
me.start();
kangkang.start();
}
}
Reentrantlock和synchronized不同,需要手动上锁手动解锁,但更灵活,我们也可以这样实现一个锁对象,也就是公平锁,说白了就是谁等的时间长谁得到锁
ReentrantLock lock=new ReentrantLock(true);
下面介绍几个方法:
wait方法:等待,是Object类中的一个方法,作用是当前线程释放自己的锁,并且让出cpu时间片,使得当前的线程进去等待队列
notify:是Object类中的一个方法,唤醒等待队列中的一个线程,使这个线程进入锁词
notifyall:唤醒所有的线程
转载:https://blog.csdn.net/jahup/article/details/106043638