我们要学习线程之前,想要知道进程这个概念,因为线程要依赖于进程,没有进程,那么也就没有线程一说。
什么是进程:正在运行的应用程序,那么很显然,你会看多个进程在运行,那么也就是说,我们的电脑是支持多进程的。
多个进程,在同一个时间点上,是同时执行的吗?不是,在单核CPU 环境下,在某一个时刻只能执行一个进程。
拿我一边放着网易云音乐,一边玩着LOL 感觉两个应用程序在同时执行呀。因为CPU可以在多个进程间进行高速的切换,
你人耳和眼睛是分辨不出来的,所以你感觉是多个应用程序在同时运行。
每一个进程中,又有很多个任务在执行,我们把这个任务称之为线程,
一个进程中至少要包含一个线程。
哪大多数的应用的程序都是多线程的,多线程的意义何在?是为了提高应用程序对CPU使用率。
进程是拥有资源的基本单位,线程是CPU调度的基本单位
进程是容器,线程要依赖于进程。
并发:多个事件在一个时间段内,高速的切换交替运行
并行:多个事件在一个时间点上同时运行
JVM 至少有两个线程,一个主线程,一个垃圾回收线程
public static void main(String[] args) {
System.out.println("主线程开始执行了");
MyThread myThread = new MyThread();
myThread.start();
MyThread myThread1 = new MyThread();
myThread1.start();
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
public void show(){
}
public void show2() {
}
}
获取线程名字的方法
public class MyTest {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
thread.setName("主线程");
String name = thread.getName();
ThreadDemo t1 = new ThreadDemo();
ThreadDemo t2 = new ThreadDemo();
ThreadDemo t3 = new ThreadDemo();
t1.setName("第一线程");
t2.setName("第二线程");
t3.setName("第三线程");
t1.start();
t2.start();
t3.start();
}
}
public class ThreadDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
Thread thread = Thread.currentThread();
String name = thread.getName();
System.out.println(name+"==="+i);
}
}
}
设置线程优先级
public static void main(String[] args) {
MyThread th1 = new MyThread();
MyThread th2 = new MyThread();
MyThread th3= new MyThread();
th1.setPriority(Thread.MAX_PRIORITY);
th2.setPriority(Thread.MIN_PRIORITY);
th1.setName("刘亦菲");
th2.setName("章子怡");
th1.start();
th2.start();
}
进程休眠演示
System.out.println("主线程执行第一句代码");
Thread.sleep(5000);
System.out.println("主线程执行第二句代码");
Thread.sleep(2000);
System.out.println("你再等两秒钟去开启子线程");
MyThread myThread = new MyThread("哈哈");
myThread.start();
加入线程
加入线程:
public final void join ()
意思就是:
等待该线程执行完毕了以后, 其他线程才能再次执行
注意事项:*/
MyThread myThread1 = new MyThread("刘备");
MyThread myThread2 = new MyThread("关羽");
MyThread myThread3 = new MyThread("张飞");
myThread1.start();
myThread1.join();
myThread2.start();
myThread2.join();
myThread3.start();
线程礼让
Thread.currentThread().setName("刘备");
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
MyThread myThread2 = new MyThread("关羽");
MyThread myThread3 = new MyThread("张飞");
myThread2.setDaemon(true);
myThread3.setDaemon(true);
myThread2.start();
myThread3.start();
打断阻塞的线程
public static void main(String[] args) throws InterruptedException {
MyThread myThread2 = new MyThread("关羽");
myThread2.start();
Thread.sleep(2000);
myThread2.interrupt();
}
public class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
@Override
public void run() {
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println(this.getName()+"=="+i);
}
}
}
Runnable接口的方式开启线程
public class MyTest6 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable);
t1.setName("老王");
t1.start();
}
}
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Thread thread = Thread.currentThread();
String name = thread.getName();
System.out.println(name+"==="+i);
}
}
}
callable接口的方式来开启线程
public class MyTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable(1000);
FutureTask<Integer> integerFutureTask = new FutureTask<>(myCallable);
Thread thread = new Thread(integerFutureTask);
thread.start();
Integer integer = integerFutureTask.get();
System.out.println(integer);
}
}
public class MyCallable implements Callable<Integer> {
int num;
public MyCallable(int i) {
num=i;
}
@Override
public Integer call() throws Exception {
Thread thread = Thread.currentThread();
String name = thread.getName();
int sum=0;
for (int i = 1; i <=num; i++) {
sum+=i;
}
return sum;
}
}
实例演示,模拟售票
public class SellTicketsThread extends Thread {
static int piao = 100;
@Override
public void run() {
while (true){
if(piao>0){
System.out.println(this.getName()+":正在出售"+(piao--)+"张票");
}
}
}
}
public class MyTest {
public static void main(String[] args) {
SellTicketsThread th1 = new SellTicketsThread();
SellTicketsThread th2= new SellTicketsThread();
SellTicketsThread th3 = new SellTicketsThread();
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
进程:正在运行的应用程序,CPU 在某一个时间点上,一次只能执行一个进程,你感觉 多个应用程序在同时进行,是因为CPU在多个进程间进行一个高速的切换。
一个应用程序可以包含很多个任务,这个任务我们称之为线程,进程是个容器,线程要依赖于进程,一个进程里面至少要包含一个线程。
进程拥有资源的基本单位,线程是cpu调度的基本单位。
我们Java中如何创建线程,有三种方式 都要使用一个 Thread
继承一个Thread类 run()
实现Runnable接口 run()
实现Callable接口 call() 抛出异常,有返回值
线程安全问题
1,是否是多线程环境
2.多个线程使用有共享资源
3.是否有多条语句在操作共享资源
synchronized (同步锁){ //锁可以是任意一个对象 多个线程使用同一把锁
有可能出现问题的代码包裹起来
}
同步代码块可以解决线程安全问题,但是,会影响性能。
使用Lock锁的方式来解决线程安全问题
public class MyTest9 {
public static void main(String[] args) {
SellRunnable sellRunnable = new SellRunnable();
Thread thread = new Thread(sellRunnable,"第一窗口");
Thread thread2 = new Thread(sellRunnable,"第二窗口");
Thread thread3 = new Thread(sellRunnable,"第三窗口");
thread.start();
thread2.start();
thread3.start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellRunnable implements Runnable{
int piao=100;
static Lock lock=new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
try {
if (piao > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("已经出售" + (piao--) + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}