java多线程学习
一、什么是线程?什么是进程?两者又有什么区别?
二、线程的状态有哪些?
三、线程的实现
注意,当用start()实现多线程的时候,线程会实现并发执行,也就是那个线程抢到了cpu那个就执行。如果用run()方法,那就是线程1执行完之后才会只能线程2,就不会有并发。
3.1,使用继承Thread方法,实现三个线程并发
- 代码线程工具类实现
public class ThreadUtil extends Thread {
public String names;
public ThreadUtil(String name) {
super();
names = name;
}
//写一个构造方法,来接通主类
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(names+" :次数 "+i);
}
}
}
- 引用类
public class MyThread {
public static void main(String[] args) {
ThreadUtil tu1 = new ThreadUtil("我是线程tu1");
ThreadUtil tu2 = new ThreadUtil("我是线程tu2");
ThreadUtil tu3 = new ThreadUtil("我是线程tu3");
tu1.start();
tu2.start();
tu3.start();
}
}
- 打印结果:
3.2,使用Runnable接口
- Runnable工具类
public class MyRunnable implements Runnable{
public String names;
public MyRunnable(String name) {
super();
names = name;
}
//写一个构造方法,来接通主类
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(names+" :次数 "+i);
}
}
}
-主类引用
public class MyThread {
public static void main(String[] args) {
MyRunnable tu1 = new MyRunnable("我是实现Runnable的线程tu1");
MyRunnable tu2 = new MyRunnable("我是实现Runnable线程tu2");
MyRunnable tu3 = new MyRunnable("我是实现Runnable线程tu3");
//切记这里不能直接,tu1.start()。你需要创建一个Thread对象来接受我们实现的线程对象
Thread tr1 = new Thread(tu1);
tr1.start();
Thread tr2 = new Thread(tu2);
tr2.start();
Thread tr3 = new Thread(tu3);
tr3.start();
}
}
- 运行结果:成功:
四、线程的常用方法
4.1代码来验证这些方法
- 代码模块:
public class TextRunnable{
public static void main(String[] args) {
TextRunnables trR = new TextRunnables("线程名称");
Thread td1 = new Thread(trR);
//来验证是否启动状态
System.out.println("线程的状态1:"+td1.isAlive());
td1.start();
System.out.println("线程的状态2:"+td1.isAlive());
//下面代码含义在于测试线程的join()强制执行的方法
for (int i = 0; i < 20; i++) {
//在主线程写一个循环,执行20次,然后当主线程执行到10的时候,强制执行子线程。如下
if (i==10) {
try {
td1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("主线程:"+i);
}
}
static class TextRunnables implements Runnable{
public String names;
public TextRunnables(String name) {
names = name;
}
//写一个构造方法,来接通主类
@Override
public void run() {
for (int i = 0; i < 5; i++) {
//获取线程的名称
System.out.println("线程名称: "+Thread.currentThread().getName());
}
}
}
}
- 1、获取线程的名称
`System.out.println("线程名称: "+Thread.currentThread().getName());
- 2、判断线程是否启动
TextRunnables trR = new TextRunnables("线程名称");
Thread td1 = new Thread(trR);
//来验证是否启动状态
System.out.println("线程的状态1:"+td1.isAlive());//打印是未启动
td1.start();
System.out.println("线程的状态2:"+td1.isAlive());//打印已经未启动
- 3、验证强制开启子线程join()方法
//下面代码含义在于测试线程的join()强制执行的方法
for (int i = 0; i < 20; i++) {
//在主线程写一个循环,执行20次,然后当主线程执行到10的时候,强制执行子线程。如下
if (i==10) {
try {
td1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("主线程:"+i);
}
}
- 剩下的还有睡眠sleep(),还有一个礼让方法yieid()方法,这里就不说了。
- -
四、线程的优先级
代码模块
public class MyRunnable02 {
public static void main(String[] args) {
//然后我们创建三个线程。来引用线程的优先级
Thread t1 = new Thread(new TextRunnables(),"A");
Thread t2 = new Thread(new TextRunnables(),"B");
Thread t3 = new Thread(new TextRunnables(),"C");
//设置优先级
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t3.setPriority(Thread.NORM_PRIORITY);
//开启线程
t1.start();
t2.start();
t3.start();
}
static class TextRunnables implements Runnable{
//写一个构造方法,来接通主类
@Override
public void run() {
for (int i = 0; i < 5; i++) {
//获取线程的名称
try {
Thread.sleep(1000);
System.out.println("线程名称: "+Thread.currentThread().getName()+i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
结果分析:优先级高,提高的是占CPU的效率,而非就一定谁的高就必须先执行
五、线程的同步
5.1:什么时候需要用到同步呢? 就是程序的资源需要给多个线程共享的时候,打个比方,火车站有5张车票 ,三个人去抢。如果没有任何管理的情况下,就会出现有人付过钱了但是没有获得票的结局。例如下方代码
public class MyRunnable02 {
public static void main(String[] args) {
//然后我们创建三个线程。来引用线程的优先级
TextRunnables fRunnables = new TextRunnables();
Thread t1 = new Thread(fRunnables);
Thread t2 = new Thread(fRunnables);
Thread t3 = new Thread(fRunnables);
//开启线程
t1.start();
t2.start();
t3.start();
}
static class TextRunnables implements Runnable{
//假设有五张牌
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//如果还有票就继续抢
if(ticket>0){
//获取线程的名称
try {
//睡眠500毫秒抢一次
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果被抢走,就减少一张票数量
System.out.println("车票剩余: "+ticket--);
}
}
}
}
}
运行结果
5.2:所以我们就要用到同步(synchronized)来分配资源,这样就好比有一个专门的售票员一样,一手交钱一手交货, 相比5.1中,也就是在处理车票数据的时候添加一个同步锁
public class MyRunnable02 {
public static void main(String[] args) {
//然后我们创建三个线程。来引用线程的优先级
TextRunnables fRunnables = new TextRunnables();
Thread t1 = new Thread(fRunnables);
Thread t2 = new Thread(fRunnables);
Thread t3 = new Thread(fRunnables);
//开启线程
t1.start();
t2.start();
t3.start();
}
static class TextRunnables implements Runnable{
//假设有五张牌
private int ticket = 5;
@Override
public void run() {
//加一个同步代码块,这样就可以合理的分配资源,不会出现cpu抢占资源问题
synchronized (this) {
for (int i = 0; i < 10; i++) {
//如果还有票就继续抢
if(ticket>0){
//获取线程的名称
try {
//睡眠500毫秒抢一次
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果被抢走,就减少一张票数量
System.out.println("车票剩余: "+ticket--);
}
}
}
}
}
}
运行结果
5.3:我们上面5.2用的是同步代码块,那我们用同步方法如何实现的,其实很简单,只需要声明一个同步的方法即可。如下:
public class MyRunnable02 {
public static void main(String[] args) {
//然后我们创建三个线程。来引用线程的优先级
TextRunnables fRunnables = new TextRunnables();
Thread t1 = new Thread(fRunnables);
Thread t2 = new Thread(fRunnables);
Thread t3 = new Thread(fRunnables);
//开启线程
t1.start();
t2.start();
t3.start();
}
static class TextRunnables implements Runnable{
//假设有五张牌
private int ticket = 5;
@Override
public void run() {
//直接调用同步方法即可
tell();
}
//写一个同步的方法
public synchronized void tell(){
for (int i = 0; i < 10; i++) {
//如果还有票就继续抢
if(ticket>0){
//获取线程的名称
try {
//睡眠500毫秒抢一次
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果被抢走,就减少一张票数量
System.out.println("车票剩余: "+ticket--);
}
}
}
}
}