目录。
-------------------------------------01------------------------------------------
15个知识点:
第一阶段:
进程,线程,协程
--------------------------------------02--------------------------------------------
代码:chapter1
package chapter1My;
public class TryConcurrency {
public static void main(String[] args) throws InterruptedException {
// readFromDataBase();
// writeDataToFile();
// Thread t1 = new Thread("threadname"){
// @Override
// public void run() {
// try {
// for(int i=0;i<1000;i++){
// System.out.println(111);
// Thread.sleep(1000L);
// }
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// };
// t1.start();
// Thread.sleep(1000*100L);
// println("223");
new Thread("read"){
@Override
public void run(){
readFromDataBase();
}
}.start();
new Thread("write"){
@Override
public void run(){
writeDataToFile();
}
}.start();
}
private static void readFromDataBase() {
try {
println("Begin read data from db.");
Thread.sleep(1000 * 30L);
println("Read data done and start handle it.");
} catch (InterruptedException e) {
e.printStackTrace();
}
println("The data handle finish and successfully.");
}
private static void writeDataToFile() {
try {
println("Begin write data to file.");
Thread.sleep(2000 * 20L);
println("Write data done and start handle it.");
} catch (InterruptedException e) {
e.printStackTrace();
}
println("The data handle finish and successfully.");
}
private static void println(String message) {
System.out.println(message);
}
}
创建线程的方法
1.直接new Thread重写里面的run方法,因为Thread是implements的Runnable的。
2.new Thread(new Runnable);
注意的点:Runnable调用run方法,里面有while循环的,循环调用的是一个方法,方法里面加锁。
锁池和等待池:https://www.cnblogs.com/tiancai/p/9371655.html
创建线程的方法:https://blog.csdn.net/qq_36390044/article/details/79274800
----------------03-------------------
线程的生命周期:
在start的时候我们做了什么事情呢?
看下start的方法:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();//native方法 是C++的 这个去调用run方法
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
看下run方法:
首先理解下这个设计模式(模版方法),算法已经定了但是其中的一些的逻辑是多变的。
package one.chapter1;
public class TemplateMethod {
public final void print(String message) {//必须是final的子类是不可以去复写的
System.out.println("################");
wrapPrint(message);
wrapPrint1(message);
System.out.println("################");
}
protected void wrapPrint(String message) {
System.out.println(555);
}
protected void wrapPrint1(String message) {
}
public static void main(String[] args) {
TemplateMethod t1 = new TemplateMethod(){
@Override
protected void wrapPrint(String message) {
System.out.println("*"+message+"*");
}
@Override
protected void wrapPrint1(String message) {
System.out.println("*"+message+"*");
}
};
t1.print("Hello Thread");
TemplateMethod t2 = new TemplateMethod(){
@Override
protected void wrapPrint(String message) {
System.out.println("+"+message+"+");
}
@Override
protected void wrapPrint1(String message) {
System.out.println("+"+message+"+");
}
};
t2.print("Hello Thread");
}
}
模版方法:https://www.runoob.com/design-pattern/template-pattern.html
总结: new runnable(ready running) block wait timewait treminate
还有一个是执行run方法的线程。
线程安全的get豆子:
多线程操作变量肯定是有问题的,第一个是刷新的问题,第二个是原子问题。
package chapter1.chapter1My;
public class GetBean {
public static void main(String[] args) {
new Thread(){
public void run(){
try {
while(true){
getBean();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
while(true){
getBean();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
while(true){
getBean();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public static int index = 100;
public static void getBean() throws InterruptedException {
// synchronized (GetBean.class){
// if(index!=0){
// Thread.sleep(10);
// index--;
// }
// }
if(index!=0){
Thread.sleep(10);
index--;
}
if(index==0){
return;
}
System.out.println(Thread.currentThread().getName()+"当前还有"+index+"个豆子");
}
}
改为runnable的
package chapter1.chapter1My;
public class getBeanRunnable {
public static void main(String[] args) {
new Thread(new DoRunn()){
}.start();
new Thread(new DoRunn()){
}.start();
new Thread(new DoRunn()){
}.start();
}
public static int index = 100;
public static void getBean() throws InterruptedException {
// synchronized (GetBean.class){
// if(index!=0){
// Thread.sleep(10);
// index--;
// }
// }
if(index!=0){
Thread.sleep(10);
index--;
}
if(index==0){
return;
}
System.out.println(Thread.currentThread().getName()+"当前还有"+index+"个豆子");
}
public static class DoRunn implements Runnable{
@Override
public void run() {
try {
while(true){
getBeanRunnable.getBean();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
runnable里面循环调方法
方法单独写
thread在new时候传参数为runnable实例
-------------------------04----------------------------------
模拟银行排队叫号:
代码:charapter2
代码:
熟悉下lambda表达式的写法。
是无序的,重复的。
i++会去主存拿但是可能其他的线程还没有刷新到主存。
--------------------------------------05----------------------------------------
Runnable的抽取。
代码:
小实验:线程本地更新缓存。
线程的三大特性:https://www.cnblogs.com/losemyfuture/p/9375336.html
线程的可见行问题:https://blog.csdn.net/ren421259121/article/details/90447853
-----------------------------06---------------------------------------------
Thread涉及到的策略模式。
代码:charapter2/calculator
策略模式的写法:
public class TaxCalculatorMain {
public static void main(String[] args) {
/*TaxCalaculator calculator = new TaxCalaculator(10000d, 2000d) {
@Override
public double calcTax() {
return getSalary() * 0.1 + getBonus() * 0.15;
}
};
double tax = calculator.calculate();
System.out.println(tax);*/
TaxCalaculator calculator = new TaxCalaculator(10000d, 2000d, (s, b) -> s + 0.3 + b * 0.1);//可以改变里面的逻辑不是改变了是重写了方法
System.out.println(calculator.calculate());
}
}
函数式编程。
-----------------------07-------------------
代码:charapter3
Thread:main线程是JVM创建的。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
Thread的命名规则是什么?
看下这个方法:
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
是静态方法。
是通过这个构造函数的。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
----
看下start方法:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
看其中的start0,其中的start0会调用run()方法。
@Override
public void run() {
if (target != null) {
target.run();
}
}
可以看到如果没有传runnable就要复写run方法。
如何在构造的时候就有一个名字呢?
线程和线程组的概念:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();//看这个代码
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
注意这个代码:
if (g == null) {
g = parent.getThreadGroup();
}
注意一点,start之后又两个线程存在的,一个是调用start方法的线程,一个是start之后的线程。
就是谁把你start了,谁就是你的parent线程。
g为null就找父亲的ThreadGroup。
看下这段代码:
执行这个代码是3。
改造下:
--------------------------08----------没看好----------------------------
线程组,ThreadGroup怎么使用是以后再讲的。
看下官方文档:
stackSize:这个参数是高度的依赖于平台的。
---
本地方法栈:NIO C++
10个线程就开辟10个虚拟机栈。
栈细分为多个栈帧,一个线程是一个栈,线程调用一次方法就有一个栈帧压栈。
代码:chapter3/CreateThread3
start0:放在本地方法栈。
栈帧有宽度和深度:10M 一个栈帧1M 深度就是10。
stackSize:创建线程改变当前线程对应的栈的深度。方法执行一次就压栈。
设置栈的深度。
package chapter3;
/***************************************
* @author:Alex Wang
* @Date:2017/2/16 QQ:532500648
* QQ交流群:286081824
***************************************/
public class CreateThread4 {
private static int counter = 1;
public static void main(String[] args) {
Thread t1 = new Thread(null, new Runnable() {
@Override
public void run() {
try {
add(1);
} catch (Error e) {
System.out.println(counter);
}
}
private void add(int i) {
counter++;
add(i + 1);
}
}, "Test", 1 << 24);
t1.start();
}
}
-----------------09---10-------------------------没看好----------
王文君的博客:https://blog.csdn.net/wangwenjun69?viewmode=list
看下博客:JVM
指针就是4个字节。
启动jvm的时候栈空间就已经确定了,栈是方法独有的。
栈帧宽度大了那深度就小了。
栈:https://blog.csdn.net/holybin/article/details/37344671
创建栈。
创建构造Thread的时候传入stackSize代表该线程占用的stack的大小。如果没有指定stackSize的大小默认是0。0代表会忽略该参数。该参数会被JNI参数去调用,另外注意该参数再有些平台有效,有些平台是无效的。
-Xss10M设置。
栈的理解:https://www.cnblogs.com/heihaozi/p/11741733.html
stackSize的理解:https://blog.csdn.net/qq_32524177/article/details/88641950
----------------------------------------11------------------------------------------