进程与线程:
- 什么是进程:就是应用程序在运行时期,所占用的内存空间区域。
一个程序也可以说是一个进程,开辟的内存可能不是连续的0-88,99-120的内存块,这样的话可能就造成了其他程序和当前的程序的数据错乱,还有一些什神奇的错误,这时候伟大的工程师,采用了虚拟内存,就是虚拟出来连续的内存,指向非连续的内存这地址)
- 什么是线程:是进程中的单个顺序控制流,是一条执行路径。
单线程:一个进程只有一个可执行的路径
多线程:一个进程有多个可执行的路径
线程的实现方式
线程是依托于进程而存在的,而进程是系统创建出去的,java并不能操作系统,但是可以调C/C++,实现创建进程,从而可以实现线程。(线程进程都是由操作系统,依靠JVM找操作系统,才能实现线程的功能)
- Thread类:继承
public class MyThread extends Thread {
@Override
public void run() {
super.run();
//线程一般执行的是耗时任务 尤其是在android 端
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
//开启线程
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
- Runnable :实现
public class RunnableDemo implements Runnable {
@Override
public void run() {
//线程一般执行的是耗时任务 尤其是在android 端
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
//开启线程
public class ThreadDemo {
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo ();
//Theand的构造方法 可以出入一个runnable对象
new Thread(runnableDemo ).start();
}
}
两种方式对比:实现接口,避免单继承局限性
这样我们就开启了两个线程,
那么,我们在继承Thread类或实现Runnable类之后,为什么要重写run()方法呢?
因为不是类中的所有代码都需要被线程执行的(个人理解继承Thread或实现Runnable的子类,不一定全是要 执行在run()方法里,可能存在其他的自定义方法,和成员变量)。而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
- 设置和获取线程的名字
Thread类的基本获取和设置方法
public final String getName():获取线程的名称。
public final void setName(String name):设置线程的名称
public class ThreadDemo {
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
Thread thread = new Thread(runnableDemo);
thread.setName("001");
System.out.println(thread.getName());
thread.start();
MyThread myThread = new MyThread();
myThread.setName("002");
System.out.println(myThread.getName());
myThread.start();
//获取当前正在执行的线程名字
System.out.println(Thread.currentThread().getName());
}
}
- 线程的操作
public static void sleep(long millis):线程休眠
public class MyThread extends Thread {
@Override
public void run() {
super.run();
//线程一般执行的是耗时任务 尤其是在android 端
try {
//当前线程被执行的时候,会每次睡眠一秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
public final void wait() :线程等待
public class MyThread extends Thread {
@Override
public void run() {
super.run();
//线程一般执行的是耗时任务 尤其是在android 端
synchronized (this) {
try {
//次线程就会被挂起,放弃CPU的执行权和释放锁,等待notify()
wait();
// wait(1000);
// wait(2000, 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
sleep()和wait()的区别:
使用上
从使用角度看,sleep是Thread线程类的静态方法,而wait是Object顶级类的费静态方法()。
sleep可以在任何地方使用(指的是当前执行的线程休眠),而wait只能在同步方法或者同步块中使用
CPU及资源锁释放
sleep,wait调用后都会暂停当前线程并让出cpu的执行时间,但不同的是sleep不会释放当前持有的对象的锁资源,到时间后会继续执行,而wait会放弃所有锁并需要notify/notifyAll后重新获取到对象锁资源后才能继续执行。
异常捕获
sleep需要捕获或者抛出异常,而wait/notify/notifyAll不需要。
为什么线程方法等待,唤醒写了Object类?
notify 等待,唤醒本锁上的线程,必须有锁的支持,锁是任意对象,将wait,notify方法写了Object类,保证任意对象锁都可以调用线程,等待唤醒方法
public final void stop():中断线程
public class StopThreadDemo {
public static void main(String[] args) {
Thread t = new Thread(new StopThread());
t.start();
t.stop();
}
}
class StopThread implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("run.........");
}
}
}
线程无任何输出,直接停止了,不再继续执行了
public void interrupt():中断线程
public class InterruptThreadDemo {
public static void main(String[] args) {
InterruptThread t = new InterruptThread();
t.start();
try {
//如果5秒 不醒来 我就弄死你
Thread.sleep(5000);
t.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class InterruptThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("线程被终止了");
}
System.out.println("run.........");
}
}
但是interrupt()方法执行后,它会终止线程的状态,还会继续执行run方法里面的代码。
线程的终止 1 stop 过时 2,interrupt 3,标记执行循环,run方法结束
public final void join():线程加入
public class JoinThread {
public static void main(String[] String) {
JoinRunnable joinRunnable1 = new JoinRunnable();
JoinRunnable joinRunnable2 = new JoinRunnable();
JoinRunnable joinRunnable3 = new JoinRunnable();
Thread t1=new Thread(joinRunnable1);
t1.setName("我是 1");
Thread t2=new Thread(joinRunnable2);
t2.setName("我是 2");
Thread t3=new Thread(joinRunnable3);
t3.setName("我是 3");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
}
}
class JoinRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName().toString());
}
}
}
等待该线程终止,使用了join方法的线程,会一直运行结束,其他线程抢CPU的资源
public static void yield():线程礼让
/**
* 线程的让步 yield
*/
public class YieldThreadDemo {
public static void main(String[] args) {
YieldRunnable yieldRunnable = new YieldRunnable();
Thread t0 = new Thread(yieldRunnable);
Thread t1 = new Thread(yieldRunnable);
t0.start();
t1.start();
}
}
class YieldRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
Thread.yield();
System.out.println(Thread.currentThread().getName() + "....run");
}
}
}
这个方法暂停当前正在执行的线程对象,并执行其他线程,出现互相谦让的状态。
让多个线程的执行更和谐,但是不能靠它保证一人一次。
public final void setDaemon(boolean on):守护线程
/**
* setDaemon(true) 守护线程
*/
public class DaemomThreadDemo {
public static void main(String[] args) {
Thread t0 = new Thread(new DaemomRunnable());
t0.setDaemon(true);//线程t0 是 main线程的守护线程,如果main执行完或者main线程终止,main的守护线程都死亡
t0.start();
}
}
class DaemomRunnable implements Runnable {
@Override
public void run() {
for (int i = 30; i > 0; i++) {
System.out.println("run........");
}
}
}
当线程设为A线程的守护线程,A死亡后,所有的守护线程都死亡
线程的运行状态图
第一次画图,见笑了,😄😄😄
- 模拟火车站卖票,引出多线程的数据安全问题
public class ThreadDemo {
public static void main(String[] args) {
RunnableDemo runnableDemo1 = new RunnableDemo();
new Thread(runnableDemo1).start();
new Thread(runnableDemo1).start();
new Thread(runnableDemo1).start();
}
}
public class RunnableDemo1 implements Runnable {
//定义一百张车票
private int mTicket = 100;
@Override
public void run() {
while (mTicket > 0) {
// 模拟卡机 让线程休眠10毫秒
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 出售车票= " + mTicket-- + " 张");
}
}
}
多线程状态下,数据出现了问题,怎么解决多线程下的数据安全问题,请看下篇