1:关于线程的理解
1.1:什么是线程?
在了解线程之前,我们不得不提到一个词"进程"。那什么是进程呢?进程是系统进行资源分配的基本单位,是操作系统结构的基础。而线程是进程的一条执行路径,也是cpu的基本单位。简单来说,当我们启动一个程序就会在系统中开展一个进程,而通过任务管理器我们就可以看到这个系统所运行的进程。

1.2:什么是线程
线程又称轻量级进程,线程是进程中的一条执行路径,也是cpu的基本调度单位。
1.3:什么是多线程
一个进程由一个或多个线程组成,并且在同一时间执行完成不同的工作
1.4:线程与进程的区别
线程就相当于进程中中独立的运行的子任务,一个线程可以包含多个进程,多个线程可以同时运行。而多线程的出现使我们更加可以更加充分的利用cpu的资源,大大提高了系统的执行能力。如果是一个单线程,那么系统的的执行能力就会特别的低下,运行效率大大降低。
2:java如何创建线程?
java中线程的的实现方式,大致有四种实现方式,目前只学会两种。
1.继续Thread;
//继承Thread
public class MyThread extends Thread{
private int takbov=100;
//重写run方法
@Override
public void run(){
for(int i=0;i<20;i++){
System.out.println("线程"+i);
}
}
}
测试类
public class Text {
public static void main(String[] args) {
// 创建一个线程
MyThread m1 =new MyThread();
//开启线程,当前线程和main主线程同时争夺CPU时间片
m1.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main"+i);
}
}
}
2.实现Runnable
public class MyRunable implements Runnable {
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"线程:"+i);
}
}
}
测试类:
public class MyRunableTest {
public static void main(String[] args) {
MyRunable m1=new MyRunable(); //线程任务
//线程对象
Thread t1=new Thread(m1,"线程A");
t1.start();
//线程对象
Thread t2=new Thread(m1,"线程B");
t2.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main线程:"+i);
}
}
}
2.1:为线程起名获取线程名称
【1】获取线程名称
(1)this.getName()必须是Thread的子类
(2)Thread.currentThread.getName();在任意位置获取线程名称
【2】为线程取名:
(1)通过调用线程对象的setName方法。
(2)通过线程子类的构造方法赋值。
package Thread;
public class Threads extends Thread{
private int takbov=100;
@Override
public void run(){
while (takbov>0){
takbov--;
//该方法可以在任何位置获取线程名:默认系统会为每个线程-- Thread-n
System.out.println(Thread.currentThread().getName()+"剩余"+takbov+"张票");
}
}
}
测试类:
package Thread;
public class Text {
public static void main(String[] args) {
Threads mo1 =new Threads();
// 通过调用对象名.setName()
mo1.setName("线程A");
//2.开启线程.start()---底层会自动调用线程的run方法,来执行该线程的任务
mo1.start();
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"==="+i);
}
}
}
3:线程中常用的方法
1.:休眠
public static void sleep(long)
作用:是当前主动休眠millis毫秒
2:放弃
public static void yield();
作用:放弃本次时间片,回到就绪状态,参与下次时间片的争夺
3:加入
public void join()
作用:允许其他线程加入当前线程,直到其他线程运行结束后。当前线程才可以运行
4:优先级
线程对象.setPriority()
作用:设置线程优先级 值1-10值越大获取cpu的概率越大。默认为5
5:守护线程
线程对象.setDaemon(true);设置守护线程。
线程有两类:守护线程(后台线程)和用户线程(前台线程)。
如果程序中所有前台线程都执行完毕,后台线程也会自动结束。
垃圾回收线程属于守护线程下
4:线程安全
如果多个程序在同时运行,而这些线程可能会同时运行这段代码。程序每次与运行这段代码的结果和单线程运行的结果是一样的,而且其他变量的值和预想的也一样,就是线程安全的。
实例:
package Thread;
public class Threads2 implements Runnable {
private int ticket = 100;
@Override
public void run() {
// 窗⼝ 永远开启
while (true) {
if (ticket > 0) {// 有票 可以卖
// 使⽤sleep模拟⼀下出票时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticket--);
}
}
}
}
测试:
public class Text2 {
public static void main(String[] args) {
// 创建线程任务对象
Threads2 ticket = new Threads2();
// 创建三个窗⼝对象
Thread t1 = new Thread(ticket, "窗⼝1");
Thread t2 = new Thread(ticket, "窗⼝2");
Thread t3 = new Thread(ticket, "窗⼝3");
// 同时卖票
t1.start();
t2.start();
t3.start();
}
}
结果出现的现象:

从中可以发现程序中出现的两个问题:
1:相同的票数
2:不存在的票数
这种几个窗口票数不同步,这种问题被称为线程安全性问题。
5:如何解决线程安全问题
当多个线程访问同一资源时,其多个线程中对资源有写的操作,就容易出现线程安全问题。
要解决这种情况我们就需要使用锁,锁定的代码都是原子操作。
锁分为两种:
1:自动锁
public class Threads2 implements Runnable {
private int ticket = 100;
@Override
public void run() {
// 窗⼝ 永远开启
while (true) {
// 自动上锁和释放锁
synchronized (this){
if (ticket > 0) {// 有票 可以卖
// 使⽤sleep模拟⼀下出票时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取当前线程对象的名字
System.out.println(Thread.currentThread().getName()+ "正在卖:" + ticket--);
}else {
break;
}
}
}
}
}
2:手动锁:Lock
package Thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Threads2 implements Runnable {
private int ticket = 100;
// 创建手动锁
private Lock l=new ReentrantLock();
@Override
public void run() {
// 窗口开启
while (true){
// 手动上锁
l.lock();
if (ticket>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--);
}else {
break;
}
// 手动释放
l.unlock();
}
}
}