标签:安全 exception 产生 默认 方法区 src 描述 底部 demo
1、多线程概述
2、启动线程的方式
3、线程生命周期
4、线程的一些方法
5、线程调度
6、线程的同步和异步
7、synchronized
8、死锁
public class Demo{
public static void main(String[] args) {
//这里属于主线程,在主栈中运行
//新建一个分支线程对象
Thread thread = new MyThread();
/*直接调用run方法,不会启动线程,
不会分配新的分支栈(单线程)*/
//thread.run();
//启动线程
thread.start();
//下面的代码还是运行在主线程中
for (int i = 0; i < 5; i++) {
System.out.println("主线程---》" + i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//编写程序,这段程序运行在分支线程中(分支栈)。
for (int i = 0; i < 5; i++) {
System.out.println("线程分支---》" + i);
}
}
}
输出:
输出结果中主线程和分支线程有多有少、有先有后是为什么?
创建出来的线程进入抢占CPU资源的状态,当线程抢到了CPU的执行权之后,线程就进入了运行状态。所以输出结果有多有少、有先有后。
public class Demo{
public static void main(String[] args) {
/*创建一个可运行的对象*/
//Runnable mr = new MyRunnable();
/*将可运行的对象封装成一个线程对象*/
//Thread thread = new Thread(mr);
/*合并代码*/
Thread thread = new Thread(new MyRunnable());
//启动线程
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程---》" + i);
}
}
}
/**这并不是一个线程类,是一个可运行的类。它还不是一个线程。*/
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程---》" + i);
}
}
}
输出(部分):
优先选择第二种。第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活。
public class Demo{
public static void main(String[] args) {
/*匿名内部类*/
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程---》" + i);
}
}
});
//启动线程
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程---》" + i);
}
}
}
输出(部分):
1、修改线程对象的名字:
void setName(String name)
将此线程的名称更改为参数 name 。
线程对象.setName("线程名字");
2、获取线程对象的名字:
String getName()
返回此线程的名称。
String name = 线程对象.getName();
3、当线程没有设置名字的时候,默认的名字规律:
Thread-0
Thread-1
Thread-2
...
4、代码示例
public class Demo{
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
myThread1.setName("t1");
System.out.println(myThread1.getName());
MyThread myThread3 = new MyThread();
System.out.println(myThread3.getName());
MyThread myThread4 = new MyThread();
System.out.println(myThread4.getName());
myThread1.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("分支线程---》" + i);
}
}
}
输出:
1、static Thread currentThread()
返回对当前正在执行的线程对象的引用。
public class Demo{
public static void main(String[] args) {
/*currentThread就是当前线程对象,
这个代码出现在main方法当中,所以当前线程就是主线程。*/
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());
//主线程名字就叫main
MyThread myThread1 = new MyThread();
myThread1.setName("t1");
System.out.println(myThread1.getName());
myThread1.start();
MyThread myThread2 = new MyThread();
myThread2.setName("t2");
System.out.println(myThread2.getName());
myThread2.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
/*currentThread就是当前线程对象。
谁执行run方法,当前线程就是谁。*/
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName() + "线程---》" + i);
}
}
}
输出:
1、static void sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
static void sleep(long millis, int nanos)
导致正在执行的线程以指定的毫秒数加上指定的纳秒数来暂停(临时停止执行),这取决于系统定时器和调度器的精度和准确性。
(放弃占有CPU时间片,让给其它线程使用。)
2、可以实现这样一种功能:
间隔特定的时间,去执行一段特定的代码,每隔多久执行一次。
3、代码示例
public class Demo{
public static void main(String[] args) {
//让当前线程休眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello kitty");
//5秒后才会输出hello kitty
}
}
4、sleep是一个静态方法,无论前面引用是什么(???.sleep
)都会转换成Thread.sleep
,并且只会使当前正在执行的线程休眠。
1、void interrupt()
中断这个线程。
2、实际不是中断线程的执行,是终止线程的阻塞状态。这种中断阻塞状态的方式依靠了java的异常处理机制。interrupt() 方法只是改变中断状态而已,它不会中断一个正在运行的线程。如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,此时调用该线程的interrupt()方法,那么该线程将抛出一个 InterruptedException中断异常。
3、例如
线程通过sleep()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
4、代码示例
public class Demo{
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.setName("t");
t.start();
//睡眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//中段t线程的睡眠
t.interrupt();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->begin");
System.out.println("5秒后输出以下信息:");
try {
Thread.sleep(1000*60);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("测试");
}
System.out.println(Thread.currentThread().getName()+"--->end");
}
}
输出:
System.out.println();
System.err.println();
1、强行终止线程的执行
2、这种方式存在很大的缺点:容易丢失数据。因为这种方式是直接将线程杀死了,线程没有保存的数据将会丢失。不建议使用。
3、代码示例
public class Demo{
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.setName("t");
t.start();
//5秒后强行终止t线程
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//该方法已过时(不建议使用)
t.stop();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i+"--->begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--->end");
}
}
输出:
代码示例:
public class Demo{
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t = new Thread(myRunnable);
t.setName("t");
t.start();
//睡眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//按意愿手动终止线程
myRunnable.run = false;
}
}
class MyRunnable implements Runnable{
//做一个布尔标记
boolean run = true;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (run){
System.out.println(Thread.currentThread().getName()+i+"--->begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
/*在终止线程之前,
加上需要执行的操作。
比如保存数据*/
System.out.println("数据以保存!");
//终止当前线程
return;
}
}
}
}
输出:
void setPriority(int newPriority)
public class Demo{
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.setPriority(10);
t.setName("t");
t.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
输出:
int getPriority()
public class Demo{
public static void main(String[] args) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName()+"默认优先级是:"+currentThread.getPriority());
Thread t = new Thread(new MyRunnable());
t.setName("t");
t.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"默认优先级是:"+thread.getPriority());
}
}
输出:
static void yield()
(让位方法)class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
//让位给主线程
if(i % 100 == 0){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
void join()
(线程合并)public class Demo{
public static void main(String[] args) {
System.out.println("main begin");
Thread t = new Thread(new MyRunnable());
t.setName("t");
t.start();
/*合并线程.
t合并到当前线程中,当前线程受阻塞,
t线程执行直到结束。*/
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main over");
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
输出:
public class Demo{
private String actno;
private double balance;
public Demo() {
}
public Demo(String actno, double balance) {
this.actno = actno;
this.balance = balance;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
//取款方法
public void withdraw(double money){
//取款之前的余额
double before = this.getBalance();
//取款之后的余额
double after = before-money;
//模拟网络延迟(睡眠一秒)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//更新余额
this.setBalance(after);
}
}
public class DemoThread extends Thread{
//两个线程共享一个账户对象
private Demo act;
//构造方法传递账户对象
public DemoThread(Demo act) {
this.act = act;
}
@Override
public void run(){
//取款操作
double money = 5000;
act.withdraw(money);
System.out.println(Thread.currentThread().getName()+
"账户"+act.getActno()+"取款"+money+"成功,余额为:"+
act.getBalance());
}
}
public class DemoTest{
public static void main(String[] args) {
//创建一个账户对象
Demo demo = new Demo("act-001",10000);
//创建两个线程
Thread t1 = new DemoThread(demo);
Thread t2 = new DemoThread(demo);
//设置name
t1.setName("t1");
t2.setName("t2");
//启动线程取款
t1.start();
t2.start();
}
}
输出:
synchronized (线程共享对象){
//线程同步代码块
}
public void withdraw(double money){
/*以下这几行代码必须是线捏排队的,不能并发。
一个线程把这里的代码全部执行结束之后,
另一个线程才能进来。*/
synchronized (this){
double before = this.getBalance();
double after = before-money;
/*这里等待1秒钟是为了延迟结束线程,
保证run方法中的输出语句中的
act.getBalance()输出的是当前线程
执行完后的余额。
如果不睡眠的话,输出语句中的信息
就会是两个线程结束后的信息,
输出的余额都为0*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
}
输出:
更多关于synchronized①
更多关于synchronized②
更多关于synchronized③
Object obj = new Object();
synchronized (obj){}
(只要是共享对象都行)synchronized (){}
大括号中的局部变量就不行)synchronized (“abc”){}
也可以,“abc”
在字符串常量池中是共享的。但是“abc”会使所有线程都同步,因为不是某几个共享的,而是所有线程共享的。MyClass mc = new MyClass();
class MyClass{
public synchronized void doSome(){ }
public void doOther(){ }
}
答:不需要,因为doOther没有synchronized关键字修饰,执行doOther不需要获取共享对象的对象锁。
class MyClass{
public synchronized void doSome(){ }
public synchronized void doOther(){ }
}
答:需要。
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
class MyClass{
public synchronized void doSome(){ }
public synchronized void doOther(){ }
}
答:不需要。因为有两个MyClass对象,两把锁。
class MyClass{
public synchronized static void doSome(){ }
public synchronized static void doOther(){ }
}
答:需要。因为这是类锁,锁的是MyClass这个类,不管创建了几个对象,这时就只有一把锁。
标签:安全 exception 产生 默认 方法区 src 描述 底部 demo
原文地址:https://www.cnblogs.com/yu011/p/13058201.html