一、进程与线程之间的区别(相关信息可参考https://www.cnblogs.com/liao13160678112/p/6603381.html)
进程:进程是一个具有一定独立功能的程序对某个数据集合的一次运行活动。
线程:(每一个任务称为一个线程)(线程与程序不同的是线程本身不能单独运行,它只能包含在程序中,只能在程序中执行)(进程创建时,同时也建立第一个线程)
1、线程是轻量级的进程;
2、没有独立的地址空间(即内存空间);
3、一个进程可拥有多个线程;
4、线程是由进程创建的;
5、线程状态有:①新建(New),②运行(Running),③等待(Waiting)/阻塞(Blocked),④就绪(Ready),⑤终止(Terminated)
所谓的并行运行并非真正的并行,而是间隔时间特短的
二、多线程的建立
第一种方法:继承Thread类,重写run方法
package com.test;
public class Demo {
public static void main(String[] args) {
Cat cat=new Cat();
//启动线程
cat.start();
}
}
class Cat extends Thread{
int times=0;
//重写run 函数
public void run()
{
while(true)
{ //休眠一秒 以毫秒为单位
try {
// sleep就会让线程进入到阻塞状态,并释放资源
Thread.sleep(1000); //这个线程会自动休息一秒休息过后 线程会自动运行
} catch (Exception e) {
// TODO: handle exception
}
times++;
System.out.println("hello,word"+times);
if(times==10)
{
break;
}
}
}
}
第二种方法:实现Runnable接口(尽量使用它)
package com.test;
public class Demo {
public static void main(String[] args) {
Dog dog=new Dog();
//创建一个线程对象
Thread t=new Thread(dog); // 必须定义个一线程对象 然后把 实现 Runnable接口的对象包括里面
//然后调用对象t的start()方法
t.start();
}
}
class Dog implements Runnable{
int times=0;
//重写run 函数
public void run()
{
while(true)
{ //休眠一秒 以毫秒为单位
try {
// sleep就会让线程进入到阻塞状态,并释放资源
Thread.sleep(1000); //这个线程会自动休息一秒休息过后 线程会自动运行
} catch (Exception e) {
// TODO: handle exception
}
times++;
System.out.println("hello,word"+times);
if(times==10)
{
break;
}
}
}
}
两种方法比较(可看https://www.cnblogs.com/lylife/p/4756981.html)
1、Java是只能继承一个父类,可以实现多个接口的一个特性,所以说采用Runnable方式可以避免Thread方式由于Java单继承带来的缺陷;
2、Runnable的代码可以被多个线程共享(Thread实例),适合于多个多个线程处理统一资源的情况。因为Runnable接口实现的只是Thread类的target,多个线程共享一个target,所以就共享其实例变量。(由于线程调度问题,可能数据不同步)
Thread.currentThread().getName()得到当前线程的名字
三、多线程原理图
让一个线程终止就是想办法让它从run()中退出
t.join()会阻塞当前线程(一般为主线程)
四、线程的同步机制:(实现多线程对同一对象的数据的同步访问)
互斥锁(解决线程调度问题)
synchronized(lock) //申请锁
{ //上锁locked
...code...
}//解锁 unlocked
①若别的线程正持有该锁,则本线程阻塞等待;
②若此锁空闲,则本线程持有锁,进入大括号内执行代码。
示例代码:(买票)
public class Demo {
public static void main(String[] args) {
//定义一个售票中心
TicketWindow tw1=new TicketWindow();
//创建三个售票点
Thread t1=new Thread(tw1);
Thread t2=new Thread(tw1);
Thread t3=new Thread(tw1);
//开始售票
t1.start();
t2.start();
t3.start();
}
}
// 售票窗口
class TicketWindow implements Runnable
{
private int nums=100;
//一共两千张
public void run()
{
while (true)
{
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
// 没上锁前
// //先判断是否有票
// if(nums>0)
// {
// //Thread.currentThread().getName() 当前线程的名字
// System.out.println(Thread.currentThread().getName()+"正在售出第"+nums+"张票");
// nums--;
// }
// else
// {
// //售票结束
// break;
// }
//
// 加了上锁
synchronized(this) //上锁 this 可以是任意一个已经定义的对象,
{
//先判断是否有票
if(nums>0)
{
//Thread.currentThread().getName() 当前线程的名字
System.out.println(Thread.currentThread().getName()+"正在售出第"+nums+"张票");
nums--;
}
else
{
//售票结束
break;
}
}
}
}
}
五、线程的通知机制(wait/notify)
注意事项:
①必须与synchronized结合使用;
②synchronized对象与wait/notify对象必须是同一个对象
。